Специальные типы TypeScript
В TypeScript есть несколько специальных типов со своим особым поведением в системе типов.
Их используют, когда тип значения заранее неизвестен или когда нужно безопасно по типам работать со значениями JavaScript, такими как null.
Примечание: эти специальные типы — часть системы типов TypeScript. Они делают ваш код безопаснее и понятнее.
Тип: any
any — самый гибкий тип в TypeScript.
Он говорит компилятору пропустить проверку типов для этой переменной.
Это бывает полезно, но применяйте его как можно реже — он отменяет всю типобезопасность TypeScript.
Когда использовать any:
- При переносе кода на JavaScript в TypeScript
- При работе с динамическим содержимым, тип которого неизвестен
- Когда нужно отключить проверку типов в одном конкретном месте
Примечание: any помогает обойти ошибки, потому что отключает проверку типов, но TypeScript больше не может вас защитить, а инструменты, которые опираются на данные о типах, например автодополнение, перестают работать.
Помните: его следует избегать любой («any») ценой...
Пример без any
В этом примере any не используется. Тип u выводится как boolean, поэтому и присваивание строки, и передача значения в Math.round — ошибки.
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 и захваченный вывод
let u = true;
u = "string"; // Ошибка: Type 'string' is not assignable to type 'boolean'.
Math.round(u); // Ошибка: Argument of type 'boolean' is not assignable to parameter of type 'number'.
Пример с any
Если задать v тип any, проверка типов отключается, и тот же самый код компилируется без ошибок.
any отключает проверку типов.
Объявите v: any = true, присвойте ему строку "string", а затем передайте v в Math.round — ни одна из строк не даёт ошибки, и ничего не выводится.
Вывод: программа на TypeScript и захваченный вывод
let v: any = true;
v = "string"; // ошибки нет, так как тип может быть "any"
Math.round(v); // ошибки нет, так как тип может быть "any"
Тип: unknown
unknown — это типобезопасный аналог any.
Он означает «здесь может быть что угодно, поэтому перед использованием нужно проверить, что это».
Главные отличия unknown от any:
- Тип
unknownнужно проверить перед использованием - Нельзя читать свойства значения типа
unknownбез утверждения типа (приведения) - Нельзя вызвать значение типа
unknownили создать через него объект
TypeScript не даст вам использовать значение типа unknown, пока вы не проверите его тип, как показано в примере.
Когда использовать unknown:
- При работе с данными из внешних источников (API, ввод пользователя и т. д.)
- Когда нужна типобезопасность, но при этом требуется гибкость
- При типобезопасном переходе с JavaScript на TypeScript
Сужение типа для unknown: значение типа unknown можно сузить до конкретного типа с помощью защитников типа, таких как typeof и Array.isArray, как в фрагменте кода ниже.
Пример
Переменная w принимает число, строку и объект. Вызвать у неё метод напрямую — ошибка; после проверки typeof и приведения вызов разрешён и выводит своё сообщение.
unknown принимает любое значение, но перед использованием его нужно проверить или привести к типу.
Объявите w: unknown = 1, затем присвойте ему строку, а потом объект с методом runANonExistentMethod, который выводит «Я мыслю, следовательно, я существую» (приведите с помощью as к объектному типу). Оставьте закомментированный прямой вызов, который дал бы ошибку "Object is of type 'unknown'", затем поставьте проверку typeof w === 'object' && w !== null и вызовите метод через приведение внутри if.
Вывод: программа на TypeScript и захваченный вывод
let w: unknown = 1;
w = "string"; // ошибки нет
w = {
runANonExistentMethod: () => {
console.log("Я мыслю, следовательно, я существую");
}
} as { runANonExistentMethod: () => void}
// Как избежать ошибки для закомментированного ниже кода, когда мы не знаем тип?
// w.runANonExistentMethod(); // Ошибка: Object is of type 'unknown'.
if(typeof w === 'object' && w !== null) {
(w as { runANonExistentMethod: Function }).runANonExistentMethod();
}
// Хотя приводить тип приходится несколько раз, мы можем сделать проверку в if, чтобы обезопасить тип и приводить его надёжнее
Сужение unknown с помощью защитников типа
Внутри каждой ветки TypeScript считает value строкой (string) или массивом, поэтому с его элементами можно работать безопасно.
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 — ошибка компиляции.
never нельзя присвоить ни одно значение.
Объявите x: never и присвойте ему true — компилятор должен сообщить об ошибке "Type 'boolean' is not assignable to type 'never'".
Вывод: программа на TypeScript и захваченный вывод
let x: never = true; // Ошибка: Type 'boolean' is not assignable to type 'never'.
Функция, которая никогда не возвращает значение
Функция, которая всегда выбрасывает ошибку, может объявить тип возвращаемого значения never.
function throwError(message: string): never {
throw new Error(message);
}
Проверка полноты с помощью never
В ветке default у shape не должно остаться ни одного случая, поэтому присваивание его переменной типа never заставит TypeScript пожаловаться, если какая-то фигура была забыта.
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.
undefined и null — это собственные типы в TypeScript.
Объявите y с типом undefined и значением undefined, а также z с типом null и значением null. Ничего не выводится.
Вывод: программа на TypeScript и захваченный вывод
let y: undefined = undefined;
let z: null = null;
Необязательные параметры и свойства
Необязательный параметр неявно имеет тип string | undefined, а необязательное свойство интерфейса — это то же самое, что number | undefined.
// 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.
// 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;