← Назад к вопросам
Для чего использовать unknown?
2.0 Middle🔥 162 комментариев
#Soft Skills и рабочие процессы
Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Для чего использовать unknown в TypeScript
unknown - это тип для значения, типа которого мы не знаем на момент разработки. Это более безопасная альтернатива any. В строгом TypeScript нужно использовать unknown вместо any.
unknown vs any
any - отключает типобезопасность полностью:
const value: any = 42;
// TypeScript не ругается, хотя value это число
value.toUpperCase(); // Ошибка будет только в runtime!
value.map(x => x * 2); // Тоже скомпилируется, но упадёт в runtime
unknown - заставляет проверить тип перед использованием:
const value: unknown = 42;
// TypeScript ошибка: Object is of type 'unknown'
value.toUpperCase();
value.map(x => x * 2);
// Нужно сначала проверить тип
if (typeof value === 'string') {
value.toUpperCase(); // OK
}
Когда использовать unknown
1. API ответы (JSON парсинг)
// Плохо: используем any
const response: any = await fetch('/api/data').then(r => r.json());
response.user.email; // Может быть undefined
// Хорошо: используем unknown и проверяем
const response: unknown = await fetch('/api/data').then(r => r.json());
if (isValidResponse(response)) {
response.user.email; // TypeScript знает структуру
}
function isValidResponse(obj: unknown): obj is ApiResponse {
return (
typeof obj === 'object' &&
obj !== null &&
'user' in obj &&
typeof (obj as any).user === 'object'
);
}
2. Обработка ошибок
// Плохо: catch получает any
try {
doSomething();
} catch (error: any) {
console.log(error.message); // Может упасть если error не Error
}
// Хорошо: используем unknown
try {
doSomething();
} catch (error: unknown) {
if (error instanceof Error) {
console.log(error.message);
} else {
console.log('Unknown error:', error);
}
}
3. localStorage / sessionStorage
// Плохо: any
const data: any = JSON.parse(localStorage.getItem('user') || 'null');
data.name; // Может быть null или не иметь свойства name
// Хорошо: unknown с проверкой
const data: unknown = JSON.parse(localStorage.getItem('user') || 'null');
interface User {
id: string;
name: string;
email: string;
}
function isUser(obj: unknown): obj is User {
return (
typeof obj === 'object' &&
obj !== null &&
'id' in obj && typeof (obj as any).id === 'string' &&
'name' in obj && typeof (obj as any).name === 'string' &&
'email' in obj && typeof (obj as any).email === 'string'
);
}
if (isUser(data)) {
console.log(data.name); // Безопасно
}
Type Guards с unknown
Функция type guard:
// Проверить, является ли значение string
function isString(value: unknown): value is string {
return typeof value === 'string';
}
// Проверить, является ли значение массивом определённого типа
function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.every(item => typeof item === 'string');
}
// Проверить, является ли значение объектом с определённой структурой
interface Post {
id: number;
title: string;
content: string;
}
function isPost(value: unknown): value is Post {
return (
typeof value === 'object' &&
value !== null &&
'id' in value && typeof (value as any).id === 'number' &&
'title' in value && typeof (value as any).title === 'string' &&
'content' in value && typeof (value as any).content === 'string'
);
}
// Использование
const unknownValue: unknown = fetchData();
if (isString(unknownValue)) {
console.log(unknownValue.toUpperCase());
} else if (isStringArray(unknownValue)) {
unknownValue.forEach(item => console.log(item));
} else if (isPost(unknownValue)) {
console.log(unknownValue.title);
}
На практике: обработка данных с сервера
interface ApiUser {
id: string;
name: string;
email: string;
age?: number;
}
function isApiUser(obj: unknown): obj is ApiUser {
if (typeof obj !== 'object' || obj === null) return false;
const typed = obj as Record<string, unknown>;
return (
typeof typed.id === 'string' &&
typeof typed.name === 'string' &&
typeof typed.email === 'string' &&
(typed.age === undefined || typeof typed.age === 'number')
);
}
async function fetchUser(id: string): Promise<ApiUser> {
const response = await fetch(`/api/users/${id}`);
const data: unknown = await response.json();
if (!isApiUser(data)) {
throw new Error('Invalid user data from API');
}
return data; // Теперь TypeScript знает, что это ApiUser
}
// Использование
try {
const user = await fetchUser('123');
console.log(user.name); // Безопасно
} catch (error: unknown) {
if (error instanceof Error) {
console.error(error.message);
}
}
Использование unknown в функциях
// Параметр unknown - функция принимает что угодно
function processValue(value: unknown): string {
if (typeof value === 'string') return value.toUpperCase();
if (typeof value === 'number') return `Number: ${value}`;
if (Array.isArray(value)) return `Array with ${value.length} items`;
return 'Unknown type';
}
processValue('hello'); // "HELLO"
processValue(42); // "Number: 42"
processValue([1, 2, 3]); // "Array with 3 items"
// Возвращаемый unknown - результат может быть любым
function getValue(key: string): unknown {
return localStorage.getItem(key);
}
const result = getValue('some-key');
if (typeof result === 'string') {
// Используем как string
}
Библиотеки для валидации
Вместо ручного type guard можно использовать валидационные библиотеки:
// Zod
import { z } from 'zod';
const UserSchema = z.object({
id: z.string(),
name: z.string(),
email: z.string().email(),
age: z.number().optional()
});
type User = z.infer<typeof UserSchema>;
const data: unknown = await fetchData();
const user = UserSchema.parse(data); // Выбросит ошибку если невалидно
// Yup
import * as yup from 'yup';
const UserSchema = yup.object().shape({
id: yup.string().required(),
name: yup.string().required(),
email: yup.string().email().required()
});
const data: unknown = await fetchData();
const user = await UserSchema.validate(data);
Сравнение подходов
// 1. any - опасно, теряем типобезопасность
const value: any = fetchData();
value.nonExistent.property(); // Компилируется, но упадёт в runtime
// 2. unknown - безопасно, требует проверки
const value: unknown = fetchData();
value.nonExistent.property(); // Ошибка компиляции!
if (typeof value === 'object' && value !== null && 'nonExistent' in value) {
// Теперь можно использовать
}
// 3. Специфичный тип - лучше всего, если известна структура
interface Data {
nonExistent?: { property: string };
}
const value: Data = fetchData();
value.nonExistent?.property; // Безопасно и без лишних проверок
Вывод
Используй unknown когда:
- Не знаешь тип данных (JSON с сервера, localStorage)
- Обрабатываешь ошибки в catch блоке
- Пишешь generic функции, которые должны работать с разными типами
- Получаешь данные из внешних источников
Преимущества unknown:
- Безопаснее any
- Требует явной проверки типа
- Ловит ошибки на этапе разработки
- Самодокументируемый код (видно, что тип неизвестен)
Правило: Никогда не используй any без очень серьёзной причины. Всегда выбирай unknown.