В чём отличие any, unknown, never?
MiddleTypeScript #typescript
Вопрос
Чем отличаются типы any, unknown и never в TypeScript?
Короткий ответ
any полностью отключает проверку типов для значения. unknown — тоже "любое значение", но безопасный: перед использованием его нужно сузить (type narrowing). never — тип значений, которых не существует, обычно означает недостижимый код или функцию, которая никогда не возвращает управление.
Подробный ответ
any— "выход" из системы типов. С переменной типаanyможно делать что угодно без ошибок компилятора: вызывать как функцию, обращаться к любым свойствам, присваивать в переменную любого другого типа. Это удобно, но лишает TypeScript смысла — ошибки всплывут только в рантайме.unknown— типобезопасная альтернативаany. В переменную типаunknownможно записать что угодно, но использовать её нельзя, пока TypeScript не убедится в конкретном типе — черезtypeof,instanceof, пользовательский type guard или явное приведение (as). Это заставляет разработчика явно обработать все возможные варианты.never— тип, у которого нет ни одного возможного значения. Используется для:- функций, которые всегда бросают исключение или уходят в бесконечный цикл (не возвращают управление);
- результата исчерпывающей проверки
switch/ifпо объединению типов (exhaustiveness check) — в ветке "не должно случиться" тип сужается доnever.
Пример
let a: any = 'hello'
a.toFixed() // компилируется без ошибки, упадёт в рантайме
let u: unknown = 'hello'
u.toUpperCase() // Error: Object is of type 'unknown'
if (typeof u === 'string') {
u.toUpperCase() // OK — тип сужен до string
}
function fail(message: string): never {
throw new Error(message)
}
type Shape = { kind: 'circle'; r: number } | { kind: 'square'; side: number }
function area(shape: Shape): number {
switch (shape.kind) {
case 'circle': return Math.PI * shape.r ** 2
case 'square': return shape.side ** 2
default:
const exhaustiveCheck: never = shape // ошибка компиляции, если забыт кейс
return exhaustiveCheck
}
}
Дополнительные вопросы
- Почему
unknownсчитается более безопасной заменойany? - Как
neverпомогает поймать забытый case вswitchна этапе компиляции? - Может ли переменная реально когда-либо иметь значение типа
never?