Где использовал unknown в TypeScript?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Где использовал unknown в TypeScript
unknown — это безопасный тип в TypeScript, который представляет значение, тип которого неизвестен. В отличие от any, unknown требует проверки типа перед использованием, что делает код более безопасным и типобезопасным.
Основное различие: any vs unknown
// any — опасно, отключает все проверки типов
const value: any = 'hello';
value.toUpperCase(); // OK (но может быть ошибка!)
value.nonExistentMethod(); // OK (ошибка в runtime!)
// unknown — безопасно, требует проверки типа
const safeValue: unknown = 'hello';
safeValue.toUpperCase(); // ошибка компилятора!
if (typeof safeValue === 'string') {
safeValue.toUpperCase(); // OK - тип проверен
}
Практические примеры использования
1. Парсинг JSON
Одна из самых частых ситуаций — парсинг JSON, когда структура неизвестна:
// Получаем JSON с сервера, но не уверены в его структуре
const jsonString = '{"user": {"name": "John", "age": 30}}';
const data: unknown = JSON.parse(jsonString);
// Неправильно - компилятор не позволит
// console.log(data.user.name); // ошибка!
// Правильно - с проверкой типа
if (typeof data === 'object' && data !== null && 'user' in data) {
const user = data.user;
if (typeof user === 'object' && user !== null && 'name' in user) {
console.log(user.name); // OK
}
}
2. Обработка ошибок
В блоке catch неизвестно, какой тип ошибки был выброшен:
try {
// Какой-то код
riskyOperation();
} catch (error: unknown) { // unknown, не Error!
// error может быть Error, String, Number или что угодно
// Нужно проверить тип
if (error instanceof Error) {
console.log('Error message:', error.message);
} else if (typeof error === 'string') {
console.log('String error:', error);
} else {
console.log('Unknown error:', error);
}
}
3. API ответы
Когда работаешь с API, ответ может иметь разную структуру:
async function fetchData(url: string): Promise<unknown> {
const response = await fetch(url);
return response.json(); // unknown
}
// Использование
const data = await fetchData('/api/users/1');
// Нужна проверка типа
function processData(data: unknown) {
if (typeof data === 'object' && data !== null) {
if ('id' in data && 'name' in data) {
// Теперь знаем, что это объект с id и name
return { id: data.id, name: data.name };
}
}
throw new Error('Invalid data format');
}
4. Event обработчики
В обработчиках событий тип часто неизвестен:
function handleChange(event: unknown) {
// event может быть Event, какой-то другой тип или null
if (event instanceof Event && event.target instanceof HTMLInputElement) {
const value = event.target.value;
console.log('Input value:', value);
} else if (typeof event === 'object' && event !== null && 'data' in event) {
console.log('Custom event data:', event.data);
}
}
5. Функция, которая принимает неизвестный аргумент
// Логирование функция, которая должна логировать что угодно
function logAnything(value: unknown) {
if (value === null) {
console.log('null');
} else if (value === undefined) {
console.log('undefined');
} else if (typeof value === 'object') {
if (Array.isArray(value)) {
console.log('Array:', value);
} else if (value instanceof Date) {
console.log('Date:', value.toISOString());
} else {
console.log('Object:', JSON.stringify(value));
}
} else if (typeof value === 'function') {
console.log('Function:', value.name || 'anonymous');
} else {
console.log('Value:', value);
}
}
logAnything(42);
logAnything([1, 2, 3]);
logAnything({ name: 'John' });
logAnything(() => {});
Создание Type Guards
Type guards — функции, которые проверяют тип и уточняют его для TypeScript:
// Type guard функция
function isUser(data: unknown): data is User {
return (
typeof data === 'object' &&
data !== null &&
'id' in data &&
'name' in data &&
typeof (data as any).id === 'number' &&
typeof (data as any).name === 'string'
);
}
interface User {
id: number;
name: string;
}
// Использование
const data: unknown = { id: 1, name: 'John' };
if (isUser(data)) {
// Здесь TypeScript знает, что data это User
console.log(data.name); // OK
}
Реальный пример из проекта
// API сервис для загрузки данных профессии
interface Profession {
id: string;
name: string;
description: string;
skills: string[];
}
async function getProfession(id: string): Promise<Profession> {
const response = await fetch(`/api/professions/${id}`);
const data: unknown = await response.json();
// Валидируем неизвестные данные
if (!isProfession(data)) {
throw new Error('Invalid profession data');
}
return data; // Теперь TypeScript знает, что это Profession
}
function isProfession(data: unknown): data is Profession {
return (
typeof data === 'object' &&
data !== null &&
'id' in data &&
'name' in data &&
'description' in data &&
'skills' in data &&
typeof (data as any).id === 'string' &&
typeof (data as any).name === 'string' &&
typeof (data as any).description === 'string' &&
Array.isArray((data as any).skills)
);
}
// Использование
const profession = await getProfession('frontend');
console.log(profession.name); // TypeScript гарантирует, что это строка
Когда использовать unknown vs any
| Ситуация | Используй |
|---|---|
| Тип неизвестен, но нужна безопасность | unknown |
| Нужна максимальная гибкость (редко) | any |
| Данные с сервера / JSON | unknown |
| Ошибки в catch блоке | unknown |
| Обработка user input | unknown |
| Динамические события | unknown |
Лучшие практики
// ПЛОХО - использование any
function process(data: any) {
return data.foo.bar; // Может сломаться, TypeScript не помогает
}
// ХОРОШО - использование unknown с проверкой
function process(data: unknown): string {
if (typeof data === 'object' && data !== null && 'foo' in data) {
const foo = data.foo;
if (typeof foo === 'object' && foo !== null && 'bar' in foo) {
return foo.bar;
}
}
throw new Error('Invalid data structure');
}
// ОТЛИЧНО - использование Type Guard
function isValidData(data: unknown): data is { foo: { bar: string } } {
return (
typeof data === 'object' &&
data !== null &&
'foo' in data &&
typeof (data as any).foo === 'object' &&
(data as any).foo !== null &&
'bar' in (data as any).foo &&
typeof (data as any).foo.bar === 'string'
);
}
function process(data: unknown): string {
if (!isValidData(data)) {
throw new Error('Invalid data structure');
}
return data.foo.bar; // Теперь TypeScript знает тип
}
Вывод
unknown использую в::
- Парсинге JSON — данные с сервера неизвестной структуры
- Обработке ошибок — catch блоки, где может быть что угодно
- API интеграции — когда ответ от API может быть разным
- Обработке пользовательского ввода — валидация форм и данных
- Event обработчиках — тип события может быть неизвестен
- Логировании — функции, которые логируют что угодно
unknown — это правильный выбор для безопасности типов. Это заставляет разработчика явно проверить тип перед использованием, что предотвращает ошибки на runtime.