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

TypeScript определяет несколько специальных типов, имеющих особое поведение в системе типов.

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

Примечание: Эти специальные типы являются частью системы типов TypeScript и помогают сделать ваш код более защищённым от ошибок и самодокументируемым.


Тип: any

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

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

Хотя это может быть полезно в некоторых ситуациях, использовать его следует умеренно, так как он отменяет функции обеспечения безопасности типов в TypeScript.

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

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

В следующем примере не используется тип any, и будет выброшена ошибка:

Пример без использования типа any


let u = true;
u = "string"; // Ошибка: Тип 'string' не может быть назначен типу 'boolean'.
Math.round(u); // Ошибка: Аргумент типа 'boolean' не может быть назначен параметру типа 'number'.

Установка переменной в особый тип any отключает проверку типов:

Пример с использованием типа any


let v: any = true;
v = "string"; // Без ошибки, так как может быть любым типом
Math.round(v); // Без ошибки, так как может быть любым типом

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

Этого следует избегать любой ценой.


Тип: unknown

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

Это безопасный способ сказать "этот тип может быть чем угодно, но вы обязаны предварительно выполнить некоторую проверку перед его использованием".

Ключевые различия между unknown и any:

  • unknown должен пройти проверку типа перед использованием.
  • Нельзя обращаться к свойствам типа unknown без утверждения типа.
  • Нельзя вызывать или конструировать значения типа unknown.

TypeScript предотвратит использование типов unknown без надлежащей проверки типа, как показано в следующем примере:

Пример


let w: unknown = 1;
w = "string"; // Без ошибки
w = {
  runANonExistentMethod: () => {
    console.log("Я мыслю, следовательно существую");
  }
} as { runANonExistentMethod: () => void };

// Как избежать ошибки, если мы не знаем тип?
// w.runANonExistentMethod(); // Ошибка: Объект типа 'unknown'.

if (typeof w === 'object' && w !== null) {
  (w as { runANonExistentMethod: Function }).runANonExistentMethod();
}

Хоть нам пришлось несколько раз приводить к типу, мы смогли провести проверку в условии if, чтобы обезопасить наше утверждение и добиться более безопасного приведения типа.

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

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

Сужение типов с unknown:

Вы можете сузить тип значения unknown с помощью проверки типа:

Пример


function processValue(value: unknown) {
  if (typeof value === 'string') {
    // value теперь рассматривается как string
    console.log(value.toUpperCase());
  } else if (Array.isArray(value)) {
    // value теперь рассматривается как any[]
    console.log(value.length);
  }
}


Тип: never

Тип never представляет тип значений, которые никогда не возникают.

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

Общие сценарии использования never:

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

Примеры использования never:

1. Функция без возврата


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

2. Проверка полноты для дискриминантных объединений


type Shape = 
  | { type: "circle"; radius: number }
  | { type: "square"; side: number }
  | { type: "triangle"; base: number; height: number };

function getArea(shape: Shape): number {
  switch (shape.type) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "square":
      return shape.side ** 2;
    case "triangle":
      return (shape.base * shape.height) / 2;
    default:
      // Компилятор выдаст ошибку, если какой‑то case пропущен
      const _exhaustiveCheck: never = shape;
      throw new Error(`Неизвестный тип фигуры: ${shape.type}`);
  }
}

3. Базовый тип never (вызывает ошибку при назначении)


let x: never = true; // Ошибка: Тип 'boolean' не может быть назначен типу 'never'.

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

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

Типы: undefined и null

В TypeScript значения undefined и null имеют свои собственные типы, подобно типам string или number.

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

Ключевые моменты о undefined и null:

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

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


let y: undefined = undefined;
let z: null = null;

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


// Необязательный параметр (неявно `string | undefined`)
function greet(name?: string) {
  return `Привет, ${name || 'незнакомец'}`;
}

// Необязательное свойство в интерфейсе
interface User {
  name: string;
  age?: number; // То же самое, что `number | undefined`
}

Ниллинговое слияние и необязательная цепочка:

Ниллинговое слияние (??): использует значение по умолчанию только в том случае, если исходное значение равно null или undefined.


const value = input ?? 'default';

Необязательная цепочка (?.): безопасно обращается к вложенным свойствам.


const street = user?.address?.street;

Важно: Эти типы наиболее полезны, когда включена опция strictNullChecks в файле tsconfig.json.

Это гарантирует, что значения null и undefined могут быть присвоены только соответствующему типу и типу any.

Чтобы включить строгие проверки null, добавьте в ваш файл tsconfig.json следующие строки:


{
  "compilerOptions": {
    "strictNullChecks": true
  }
}