Типы `unknown` и `any` в TypeScript: в чем разница и когда что использовать?
Ключевое отличие: безопасность типов
Главное различие между any и unknown заключается в том, как TypeScript обрабатывает эти типы при выполнении операций. any полностью отключает проверку типов, в то время как unknown требует явной проверки перед использованием.
Тип any: "отключи TypeScript"
Когда вы используете any, вы говорите компилятору: "Не проверяй этот тип, я знаю, что делаю". Это означает, что вы можете вызывать любые методы и свойства на значении типа any без ошибок компиляции, даже если эти методы не существуют:
let value: any = "hello";
value.toUpperCase(); // ✅ OK (но в рантайме действительно существует)
value.nonExistentMethod(); // ✅ OK в TypeScript, но ❌ ошибка в рантайме
value.some.property.path; // ✅ OK, но может упасть в рантайме
Проблема в том, что вы теряете все преимущества TypeScript — автодополнение, проверку типов, рефакторинг. Ошибки, которые могли быть найдены на этапе компиляции, переходят в рантайм.
Тип unknown: "безопасное хранилище"
unknown — это type-safe аналог any. Вы можете присвоить unknown что угодно, но не можете использовать значение без предварительной проверки типа:
let value: unknown = "hello";
value.toUpperCase(); // ❌ Ошибка: Object is of type 'unknown'
// Правильный подход — сузить тип через проверку
if (typeof value === "string") {
value.toUpperCase(); // ✅ OK, теперь TypeScript знает, что это string
}
Когда что использовать?
- Используйте
unknownкогда:- Получаете данные из внешних источников (API, пользовательский ввод)
- Пишете функции, которые должны работать с разными типами, но требуют проверки
- Хотите заставить других разработчиков (или себя) явно проверять типы
- Используйте
anyтолько когда:- Мигрируете JavaScript-проект на TypeScript и временно не можете типизировать все
- Работаете с очень динамичными структурами, где типизация невозможна
- Нужно быстро прототипировать (но потом лучше заменить на
unknown)
Практический пример: обработка API-ответа
// Плохо — с any
function processApiResponse(response: any) {
// Никакой защиты, любая опечатка приведет к ошибке
console.log(response.user.name.toUpperCase());
}
// Хорошо — с unknown
function processApiResponseSafe(response: unknown) {
if (response && typeof response === "object" && "user" in response) {
const user = (response as { user: { name: string } }).user;
if (typeof user.name === "string") {
console.log(user.name.toUpperCase());
}
}
}
Дополнительные возможности: type guards и утверждения
Вы можете создавать собственные type guards для работы с unknown:
function isUser(obj: unknown): obj is { name: string; age: number } {
return (
typeof obj === "object" &&
obj !== null &&
"name" in obj &&
typeof (obj as any).name === "string" &&
"age" in obj &&
typeof (obj as any).age === "number"
);
}
function processUser(data: unknown) {
if (isUser(data)) {
console.log(`User: ${data.name}, ${data.age}`); // ✅ Безопасно
}
}
Вывод: Всегда отдавайте предпочтение unknown перед any. any — это "красная кнопка", которая отключает TypeScript. unknown — это безопасный контейнер, который заставляет вас явно проверять типы, делая код надежнее.
Альтернативный взгляд: когда any все-таки оправдан
Хотя unknown почти всегда лучше, есть несколько сценариев, где any может быть осознанным выбором:
1. Сложные дженерики и декораторы
// Иногда нужно передать "что угодно" через цепочку функций
function pipe(...fns: Array<(arg: any) => any>): (arg: any) => any {
return (arg: any) => fns.reduce((acc, fn) => fn(acc), arg);
}
Здесь any используется намеренно, потому что мы не можем предсказать все возможные комбинации типов.
2. Работа с Reflect API или Proxy
const handler: ProxyHandler<any> = {
get(target: any, prop: string) {
return prop in target ? target[prop] : undefined;
}
};
3. Быстрая миграция с JavaScript
Если вы переносите большой JS-проект, можно временно использовать any для всего, что не удалось типизировать сразу. Но обязательно помечайте такие места комментарием // TODO: заменить на unknown.
Важное правило
Если вы используете any, спросите себя: "Могу ли я заменить его на unknown с type guard?" Если ответ "да" — сделайте это. Если "нет" — убедитесь, что у вас действительно веская причина использовать any, и задокументируйте её.
Ответов пока нет.
Войдите чтобы оставить ответ