Перейти к основному содержимому

Специальные типы TypeScript

В TypeScript есть несколько специальных типов со своим особым поведением в системе типов.

Их используют, когда тип значения заранее неизвестен или когда нужно безопасно по типам работать со значениями JavaScript, такими как null.

Примечание: эти специальные типы — часть системы типов TypeScript. Они делают ваш код безопаснее и понятнее.


Тип: any

any — самый гибкий тип в TypeScript.

Он говорит компилятору пропустить проверку типов для этой переменной.

Это бывает полезно, но применяйте его как можно реже — он отменяет всю типобезопасность TypeScript.

Когда использовать any:

  • При переносе кода на JavaScript в TypeScript
  • При работе с динамическим содержимым, тип которого неизвестен
  • Когда нужно отключить проверку типов в одном конкретном месте

Примечание: any помогает обойти ошибки, потому что отключает проверку типов, но TypeScript больше не может вас защитить, а инструменты, которые опираются на данные о типах, например автодополнение, перестают работать.

Помните: его следует избегать любой («any») ценой...

Пример без any

В этом примере any не используется. Тип u выводится как boolean, поэтому и присваивание строки, и передача значения в Math.round — ошибки.

Prompt
Покажите, какие ошибки возникают без any, когда переменная используется как значение разных типов. Объявите u = true (выводится тип boolean), присвойте ему строку "string", а затем передайте u в Math.round — обе строки не должны компилироваться: "Type 'string' is not assignable to type 'boolean'" и "Argument of type 'boolean' is not assignable to parameter of type 'number'".
Вывод: программа на TypeScript и захваченный вывод

Пример с any

Если задать v тип any, проверка типов отключается, и тот же самый код компилируется без ошибок.

Prompt
Покажите, что тип any отключает проверку типов. Объявите v: any = true, присвойте ему строку "string", а затем передайте v в Math.round — ни одна из строк не даёт ошибки, и ничего не выводится.
Вывод: программа на TypeScript и захваченный вывод

Тип: unknown

unknown — это типобезопасный аналог any.

Он означает «здесь может быть что угодно, поэтому перед использованием нужно проверить, что это».

Главные отличия unknown от any:

  • Тип unknown нужно проверить перед использованием
  • Нельзя читать свойства значения типа unknown без утверждения типа (приведения)
  • Нельзя вызвать значение типа unknown или создать через него объект

TypeScript не даст вам использовать значение типа unknown, пока вы не проверите его тип, как показано в примере.

Когда использовать unknown:

  • При работе с данными из внешних источников (API, ввод пользователя и т. д.)
  • Когда нужна типобезопасность, но при этом требуется гибкость
  • При типобезопасном переходе с JavaScript на TypeScript

Сужение типа для unknown: значение типа unknown можно сузить до конкретного типа с помощью защитников типа, таких как typeof и Array.isArray, как в фрагменте кода ниже.

Пример

Переменная w принимает число, строку и объект. Вызвать у неё метод напрямую — ошибка; после проверки typeof и приведения вызов разрешён и выводит своё сообщение.

Prompt
Покажите, что unknown принимает любое значение, но перед использованием его нужно проверить или привести к типу. Объявите w: unknown = 1, затем присвойте ему строку, а потом объект с методом runANonExistentMethod, который выводит «Я мыслю, следовательно, я существую» (приведите с помощью as к объектному типу). Оставьте закомментированный прямой вызов, который дал бы ошибку "Object is of type 'unknown'", затем поставьте проверку typeof w === 'object' && w !== null и вызовите метод через приведение внутри if.
Вывод: программа на TypeScript и захваченный вывод

Сужение unknown с помощью защитников типа

Внутри каждой ветки TypeScript считает value строкой (string) или массивом, поэтому с его элементами можно работать безопасно.

script.ts
function processValue(value: unknown) {
  if (typeof value === 'string') {
    // value is now treated as string
    console.log(value.toUpperCase());
  } else if (Array.isArray(value)) {
    // value is now treated as any[]
    console.log(value.length);
  }
}

Тип: never

never — это тип значений, которых никогда не бывает.

Он говорит, что что-то никогда не происходит или не должно происходить.

Типичные случаи применения never:

  • Функции, которые никогда не возвращают значение (они всегда выбрасывают ошибку или работают бесконечно)
  • Защитники типа, которые никогда не проходят проверку типов
  • Проверка полноты разбора размеченных объединений

Фрагменты кода ниже показывают never в действии, а пример показывает, что произойдёт, если попытаться присвоить ему значение.

Когда использовать never:

  • Для функций, которые никогда не вернут значение
  • В защитниках типа, которые никогда не должны срабатывать
  • Для полной проверки типов в инструкциях switch
  • В обобщённых типах, чтобы пометить некоторые случаи как невозможные

Базовый тип never

Типу never нельзя присвоить ни одно значение, поэтому присваивание true — ошибка компиляции.

Prompt
Покажите, что типу never нельзя присвоить ни одно значение. Объявите x: never и присвойте ему true — компилятор должен сообщить об ошибке "Type 'boolean' is not assignable to type 'never'".
Вывод: программа на TypeScript и захваченный вывод

Функция, которая никогда не возвращает значение

Функция, которая всегда выбрасывает ошибку, может объявить тип возвращаемого значения never.

script.ts
function throwError(message: string): never {
  throw new Error(message);
}

Проверка полноты с помощью never

В ветке default у shape не должно остаться ни одного случая, поэтому присваивание его переменной типа never заставит TypeScript пожаловаться, если какая-то фигура была забыта.

script.ts
type Shape = Circle | Square | Triangle;

function getArea(shape: Shape): number {
  switch (shape.kind) {
    case 'circle':
      return Math.PI * shape.radius ** 2;
    case 'square':
      return shape.sideLength ** 2;
    default:
      // TypeScript knows this should never happen
      const _exhaustiveCheck: never = shape;
      return _exhaustiveCheck;
  }
}

Тип: undefined и null

В TypeScript у undefined и null есть собственные типы, так же как у string или number.

По умолчанию эти значения можно присвоить любому другому типу. Это поведение меняется строгими проверками на null в TypeScript.

Главное про undefined и null:

  • undefined означает, что переменная объявлена, но ей ни разу не присвоили значение
  • null — это явное присваивание, означающее «нет значения» или «нет объекта»
  • В TypeScript у обоих есть свои типы: undefined и null
  • При включённой опции strictNullChecks эти типы нужно обрабатывать явно

Необязательные параметры и свойства — знак ? после имени параметра или свойства делает его необязательным, что добавляет undefined к его типу.

Оператор нулевого слияния и опциональная цепочка — ?? подставляет значение по умолчанию только тогда, когда значение равно null или undefined, а ?. читает вложенные свойства, не падая, если чего-то в цепочке нет.

Важно: эти типы наиболее полезны, когда в вашем tsconfig.json включена опция strictNullChecks. Тогда null и undefined можно присвоить только самим себе и типу any.

Чтобы включить строгие проверки на null, добавьте "compilerOptions": { "strictNullChecks": true } в ваш tsconfig.json.

Базовое использование

Переменная y имеет тип undefined, а переменная z — тип null.

Prompt
Покажите, что undefined и null — это собственные типы в TypeScript. Объявите y с типом undefined и значением undefined, а также z с типом null и значением null. Ничего не выводится.
Вывод: программа на TypeScript и захваченный вывод

Необязательные параметры и свойства

Необязательный параметр неявно имеет тип string | undefined, а необязательное свойство интерфейса — это то же самое, что number | undefined.

script.ts
// Optional parameter (implicitly `string | undefined`)
function greet(name?: string) {
  return `Hello, ${name || 'stranger'}`;
}

// Optional property in an interface
interface User {
  name: string;
  age?: number;  // Same as `number | undefined`
}

Нулевое слияние и опциональная цепочка

?? подставляет «default» только для null или undefined, а ?. безопасно читает user.address.street.

script.ts
// Nullish coalescing (??) - only uses default if value is null or undefined
const value = input ?? 'default';

// Optional chaining (?.) - safely access nested properties
const street = user?.address?.street;