Type guards
Type guard — проверка, которая сужает тип. TypeScript понимает такие проверки и даёт доступ к полям.
typeof
function print(value: string | number) {
if (typeof value === 'string') {
console.log(value.toUpperCase());
} else {
console.log(value.toFixed(2));
}
}
Работает со string, number, boolean, symbol, undefined, object, function.
in
Проверяет наличие свойства:
type A = { a: string };
type B = { b: number };
function handle(value: A | B) {
if ('a' in value) {
console.log(value.a);
} else {
console.log(value.b);
}
}
instanceof
Для классов:
class Dog { bark() {} }
class Cat { meow() {} }
function sound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark();
} else {
animal.meow();
}
}
Array.isArray
function print(value: string | string[]) {
if (Array.isArray(value)) {
value.forEach((v) => console.log(v));
} else {
console.log(value);
}
}
Литеральный дискриминатор
type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'square'; side: number };
function area(shape: Shape) {
if (shape.kind === 'circle') {
return Math.PI * shape.radius ** 2;
}
return shape.side ** 2;
}
Пользовательские type guards
Функция с возвращаемым типом value is Type:
function isString(value: unknown): value is string {
return typeof value === 'string';
}
function print(value: unknown) {
if (isString(value)) {
console.log(value.toUpperCase());
}
}
Guard для объектов
type User = { name: string; email: string };
function isUser(value: unknown): value is User {
return (
typeof value === 'object' &&
value !== null &&
'name' in value &&
typeof (value as User).name === 'string'
);
}
if (isUser(data)) {
console.log(data.name);
}
Guard для массива
function isUserArray(value: unknown): value is User[] {
return Array.isArray(value) && value.every(isUser);
}
Проверка на null
if (value !== null) {
//
}
if (value != null) { // null и undefined
//
}
Assertion functions
function assert(condition: unknown, message: string): asserts condition {
if (!condition) throw new Error(message);
}
function print(value: string | null) {
assert(value !== null, 'Value is null');
console.log(value.toUpperCase());
}
asserts condition — после вызова TypeScript уверен в условии.
Assertion для типа
function assertIsString(value: unknown): asserts value is string {
if (typeof value !== 'string') {
throw new Error('Not a string');
}
}
Guard и discriminated unions
Дискриминатор — самый надёжный guard для union объектов:
type Notification =
| { kind: 'email'; address: string }
| { kind: 'sms'; phone: string };
function send(n: Notification) {
if (n.kind === 'email') {
// n: { kind: 'email'; address: string }
}
}
Когда создавать guard
- Данные из API (валидация)
- Парсинг JSON
- Обработка
unknown - Сложные проверки формы
- Многократное использование проверки
Итоги
- Type guards сужают тип
- Встроенные:
typeof,in,instanceof,Array.isArray - Пользовательские —
value is Type - Assertion —
asserts condition - Дискриминатор — самый надёжный
- Полезно для API и
unknown