Специальные типы TypeScript: never, void, unknown, any
В TypeScript есть четыре специальных типа: never, void, unknown и any.
Они играют важную роль в системе типов. Понимание их различий крайне важно для написания типобезопасного кода.
SVG-диаграмма: сравнение специальных типов
Зачем нужны специальные типы
Система типов TypeScript очень мощна. Помимо обычных типов, она предоставляет четыре специальных типа для работы с конкретными сценариями.
Понимание различий между этими четырьмя специальными типами помогает нам писать более безопасный и точный типизированный код.
Пояснение концепции:never, void, unknown и any — это специальные типы TypeScript, каждый из которых имеет различное значение и варианты использования.
Тип never
never представляет тип, который никогда не возвращает управление. Обычно он используется для функций, которые выбрасывают исключения или бесконечно зацикливаются.
Пример
// Функция никогда не завершается нормально; она всегда выбрасывает ошибку
function throwError(message: string): never {
throw new Error(message);
}
// Функция с бесконечным циклом
// Функция никогда не возвращает управление; программа продолжает выполняться
function infiniteLoop(): never {
while (true) {
console.log("Работает...");
}
}
// never является подтипом всех типов
// Это означает, что never можно присвоить любому типу
var neverValue: never;
var num: number = neverValue; // Верно: never является подтипом number
console.log("never присваивается number: " + num);
Вывод:
never 赋值给 number: undefined
Важно:never является подтипом всех типов, что означает, что never можно присвоить любому типу, но никакой тип нельзя присвоить never (кроме самого never).
Тип void
void означает, что возвращаемого значения нет, и обычно используется для объявления функций, у которых нет оператора return.
Пример
// Функция не имеет возвращаемого значения после выполнения
function logMessage(message: string): void {
console.log("Лог: " + message);
// Нет оператора return или return undefined
}
logMessage("Привет");
// переменная void (редко используется)
// Можно присвоить только undefined
var empty: void = undefined;
console.log("переменная void: " + empty);
Вывод:
日志: Hello void 变量: undefined
Объяснение:void фактически очень похож на undefined и в основном используется для объявлений типа возвращаемого значения функции, указывая, что функция не имеет возвращаемого значения.
Тип unknown
unknown — это типобезопасный any. При использовании unknown необходимо выполнить проверку типов перед его использованием.
Пример
// Это "безопасный" any
var value: unknown = "hello";
value = 42;
value = true;
// Тип unknown нельзя напрямую присвоить другим типам
// Если вы раскомментируете следующую строку, компилятор сообщит об ошибке
// var str: string = value;
// Его можно присвоить только после проверки типов
if (typeof value === "string") {
// TypeScript знает, что value имеет тип string
var str: string = value;
console.log("String length: " + str.length);
}
Вывод:
字符串长度: 5
Безопасность:unknown требует проверки типов перед использованием, что защищает безопасность типов. При работе с данными из неизвестных источников следует использовать unknown вместо any.
Тип any
any полностью обходит проверку типов, и ему можно присвоить любой тип. Это наименее безопасный тип в TypeScript.
Пример
// Полностью обходит проверку типов
var anything: any = "hello";
anything = 42;
anything = true;
// any можно присвоить любому типу
// Это нарушает типобезопасность
var str: string = anything;
var num: number = anything;
console.log("Строка: " + str);
console.log("Число: " + num);
// Объект типа any может вызвать любой метод
// Компилятор не сообщит об ошибке, но во время выполнения может произойти сбой
var obj: any = {};
obj.foo(); // Ошибка не возникает, но метод foo на самом деле не существует
obj.bar = "value";
Предупреждение:Тип any полностью обходит проверку типов TypeScript, и его следует по возможности избегать. Если его все же нужно использовать, убедитесь, что тип значения верен.
Сравнение any и unknown
И any, и unknown могут принимать любой тип, но их безопасность совершенно разная.
| Характеристика | any | unknown |
|---|---|---|
| Принимает любой тип | ✓ Да | ✓ Да |
| Напрямую присваивается другим типам | ✓ Да | ✗ Нет (требуется проверка) |
| Прямой вызов методов | ✓ Да | ✗ Нет (требуется проверка) |
| Типобезопасность | ✗ Отсутствует | ✓ Да |
Рекомендация:При обработке данных неизвестных типов предпочитайте unknown вместо any, так как это заставляет выполнять проверку типов.
never против void
И never, и void используются для типов возвращаемого значения функций, но их смысл совершенно разный.
| Характеристика | never | void |
|---|---|---|
| Значение | Никогда не возвращает | Нет возвращаемого значения |
| Используется для функций | Выброс исключений / бесконечные циклы | Обычные функции без возвращаемого значения |
| Присваивается другим типам | ✓ Да (подтип) | Присваивается только void/any |
Ключевое различие:never означает, что функция никогда не возвращает управление нормально (либо выбрасывает исключение, либо входит в бесконечный цикл); void означает, что функция выполняется нормально, но не имеет возвращаемого значения.
Практическое применение: исчерпывающая проверка
Важное применение типа never — выполнение исчерпывающих проверок, гарантирующих, что все возможные случаи обработаны.
Пример
type Shape = { kind: "circle", radius: number }
| { kind: "square", side: number };
// Вычислить площадь фигуры
function area(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "square":
return shape.side ** 2;
default:
// Ветка по умолчанию должна обрабатывать все непредвиденные случаи
// Если вы добавите новый тип Shape, но забудете его обработать, компилятор сообщит об ошибке
var _exhaustive: never = shape;
return _exhaustive;
}
}
var circle = { kind: "circle" as const, radius: 5 };
var square = { kind: "square" as const, side: 4 };
console.log("Площадь круга: " + area(circle).toFixed(2));
console.log("Площадь квадрата: " + area(square));
Вывод:
圆形面积: 78.54 正方形面积: 16
Исчерпывающая проверка:Этот паттерн гарантирует, что при добавлении новой ветки типа, если вы забудете обработать её в switch, компилятор сообщит об ошибке, потому что новый тип нельзя присвоить never.
Примечания
- never — это подтип:never можно присвоить любому типу, но никакой тип нельзя присвоить never
- void vs undefined:В JavaScript void и undefined по сути эквивалентны
- unknown требует проверки:Прежде чем использовать значение типа unknown, необходимо выполнить проверку типа.
- Избегайте any:Старайтесь не использовать any; предпочитайте unknown.
Лучшие практики:Безопасность типов от самой высокой к самой низкой: never > void > unknown > any. Используйте более безопасные типы, когда это возможно.
Итог
Понимание этих четырёх специальных типов очень важно для написания высококачественного кода на TypeScript.
- never:Никогда не возвращает значение; используется для исчерпывающих проверок; является подтипом всех типов.
- void:Не возвращает значение; используется для обычных функций, которые не возвращают значение.
- unknown:Безопасный произвольный тип; перед использованием необходимо выполнить проверку типа.
- any:Обходит все проверки типов; этого следует по возможности избегать.
Другие расширенияРекомендации:При написании кода предпочитайте более строгие типы. Используйте unknown для неизвестных данных, void для функций без возвращаемого значения и never, когда необходимы исчерпывающие проверки.