Введение: почему эта тема взорвала Stack Overflow?
Если вы когда-нибудь писали на TypeScript, то наверняка сталкивались с дилеммой: unknown или any? Вопрос, собравший тысячи просмотров на Stack Overflow, не теряет актуальности и в 2025 году. Кажется, что оба типа позволяют хранить что угодно — так в чём же разница?
Представьте, что вы строите дом. any — это дверь, открытая настежь для всех, включая грабителей. unknown — дверь с замком и видеоглазком: вы сначала проверите, кто пришёл, а потом уже пускаете. В этой статье мы разберёмся, почему unknown стал золотым стандартом безопасности в TypeScript, а any — злом, которое иногда бывает оправдано.
Мы не просто перескажем документацию. Мы покажем реальные кейсы из практики 2025 года, разберём лучшие практики и дадим чёткий алгоритм выбора. Поехали!
Что такое any и почему его все боятся?
any — это самый "гибкий" тип в TypeScript. Он буквально говорит компилятору: "Отключи систему типов, я знаю, что делаю". Звучит как суперсила, но на деле это бомба замедленного действия.
Пример: как any ломает типы
function processUser(user: any) {
console.log(user.name.toUpperCase()); // Ошибка в рантайме, если user — null
}
processUser(null); // TypeError: Cannot read property 'toUpperCase' of null
Компилятор TypeScript даже не предупредит вас об этом! any отключает все проверки, и ошибка вылезет только в продакшене. В 2025 году, когда проекты становятся сложнее, такой подход — путь к хаосу.
Когда any всё-таки полезен?
- Миграция с JavaScript: когда вы переписываете старый проект,
any— временный костыль. - Динамические данные: например, ответы от внешних API, где структура меняется.
- Тесты: в моках иногда проще использовать
any, чем описывать сложные типы.
Но помните: any — это как кредитная карта с бесконечным лимитом. Удобно, пока не придёт счёт.
Unknown: строгий охранник на входе
unknown появился в TypeScript 3.0 как безопасная альтернатива any. Он тоже может содержать любое значение, но запрещает с ним работать без явной проверки. Это тип-контейнер, который требует верификации.
Пример: unknown в действии
function processUser(user: unknown) {
// Ошибка компиляции! Свойство 'name' не существует на типе 'unknown'
// console.log(user.name.toUpperCase());
// Нужна проверка
if (user && typeof user === 'object' && 'name' in user) {
const typedUser = user as { name: string };
console.log(typedUser.name.toUpperCase()); // Всё ок
}
}
processUser({ name: "Alice" }); // ALICE
processUser(null); // Ничего не упадёт
Заметили разницу? unknown не даёт вам стрелять себе в ногу. Вы обязаны проверить тип перед использованием. Это и есть безопасная типизация.
Сравнение any vs unknown в таблице
Чтобы закрепить материал, давайте посмотрим на ключевые отличия:
| Критерий | any | unknown |
|---|---|---|
| Присвоение любого значения | ✅ Да | ✅ Да |
| Доступ к свойствам без проверки | ✅ Да | ❌ Нет |
| Присвоение другому типу | ✅ Любому | ❌ Только any или unknown |
| Защита от ошибок в рантайме | ❌ Нет | ✅ Да (требует проверки) |
Как видите, unknown побеждает по всем пунктам безопасности. Но есть нюанс...
Лучшие практики 2025: когда что использовать
Опираясь на опыт сообщества и реальные проекты, вот чек-лист для принятия решения:
Используйте unknown, если:
- Вы получаете данные из ненадёжного источника (API, пользовательский ввод, JSON).
- Вы пишете библиотеку и хотите, чтобы пользователь сам проверял типы.
- Вы работаете с рекурсивными или гетерогенными структурами данных.
Используйте any, если:
- Вы мигрируете с JavaScript и не хотите переписывать всё сразу.
- Вы пишете прототип или хак для хакатона (но обещайте потом переписать!).
- Вы работаете с рефлексией или метапрограммированием, где типы физически нельзя проверить.
Но самый важный совет на 2025 год: избегайте any в коде, который пойдёт в продакшен. Используйте unknown + type guards (защитники типа).
Продвинутые техники работы с unknown
В 2025 году сообщество выработало несколько паттернов, которые делают работу с unknown удобной и элегантной.
Паттерн 1: Type guard-функции
function isUser(obj: unknown): obj is { name: string; age: number } {
return (
typeof obj === 'object' &&
obj !== null &&
'name' in obj &&
'age' in obj &&
typeof (obj as any).name === 'string' &&
typeof (obj as any).age === 'number'
);
}
function greet(user: unknown) {
if (isUser(user)) {
console.log(`Привет, ${user.name}! Тебе ${user.age} лет.`);
} else {
console.log('Это не пользователь');
}
}
Такие функции можно переиспользовать во всём проекте. Это как создать свой собственный "швейцарский нож" для проверки типов.
Паттерн 2: Z-схема (Zod или Yup)
В 2025 году валидация на уровне рантайма стала стандартом де-факто. Библиотеки вроде zod позволяют описать схему и автоматически вывести тип:
import { z } from 'zod';
const UserSchema = z.object({
name: z.string(),
age: z.number().positive(),
});
type User = z.infer<typeof UserSchema>;
function processUnknown(data: unknown): User {
const result = UserSchema.safeParse(data);
if (!result.success) {
throw new Error('Невалидные данные');
}
return result.data; // Тип