Специальные типы TypeScript: never, void, unknown, any

В TypeScript есть четыре специальных типа: never, void, unknown и any.

Они играют важную роль в системе типов. Понимание их различий крайне важно для написания типобезопасного кода.


SVG-диаграмма: сравнение специальных типов Background Title Comparison of Four Special Types any Arbitrary type Bypasses type checking No safety unknown Safe arbitrary type Requires checking before use Has safety void No return value Used for functions Can return undefined never Never returns Throws exception / loops Subtype of all types Arrow marker Lower section: type safety levels Type safety levels Level 1 any (lowest) Completely bypasses type checking Level 2 unknown Requires type checking before use Level 3 void Function has no return value Level 4 never (highest) Strictest and safest

Зачем нужны специальные типы

Система типов 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 необходимо выполнить проверку типов перед его использованием.

Пример

// 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.

Пример

// any может быть любым типом
// Полностью обходит проверку типов
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, когда необходимы исчерпывающие проверки.

Другие расширения