JavaScript & TypeScriptМодуль 8: Продвинутый TypeScript
Type Guards
Сужение типов в TypeScript
Цель урока
В этом уроке ты научишься:
- Использовать встроенные type guards
- Создавать пользовательские guards
- Применять assertion functions
typeof
function process(value: string | number) {
if (typeof value === "string") {
console.log(value.toUpperCase()); // string
} else {
console.log(value.toFixed(2)); // number
}
}instanceof
class Dog {
bark() { console.log("Гав!"); }
}
class Cat {
meow() { console.log("Мяу!"); }
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark();
} else {
animal.meow();
}
}in
type Fish = { swim: () => void };
type Bird = { fly: () => void };
function move(animal: Fish | Bird) {
if ("swim" in animal) {
animal.swim();
} else {
animal.fly();
}
}Пользовательские Type Guards
interface User {
type: "user";
name: string;
}
interface Admin {
type: "admin";
name: string;
permissions: string[];
}
// Type guard функция
function isAdmin(person: User | Admin): person is Admin {
return person.type === "admin";
}
function greet(person: User | Admin) {
if (isAdmin(person)) {
console.log("Админ: " + person.permissions.length + " прав");
} else {
console.log("Пользователь: " + person.name);
}
}Truthiness Narrowing
function printName(name: string | null | undefined) {
if (name) {
console.log(name.toUpperCase()); // string
} else {
console.log("Имя не указано");
}
}Equality Narrowing
function compare(a: string | number, b: string | boolean) {
if (a === b) {
// Оба должны быть string
console.log(a.toUpperCase());
}
}Assertion Functions
function assertIsString(value: unknown): asserts value is string {
if (typeof value !== "string") {
throw new Error("Не строка!");
}
}
function process(value: unknown) {
assertIsString(value);
// После assert TypeScript знает, что value — string
console.log(value.toUpperCase());
}Discriminated Unions
type Circle = { kind: "circle"; radius: number };
type Square = { kind: "square"; side: number };
type Shape = Circle | Square;
function getArea(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "square":
return shape.side ** 2;
}
}Практика
Задание 1: typeof guard
Задача: Создай функцию stringify.
Запустите код для проверки
Loading...
Ваш вывод:
Ожидаемый результат:
HELLO 42.00 yes
Задание 2: Пользовательский guard
Задача: Создай type guard для проверки массива.
Запустите код для проверки
Loading...
Ваш вывод:
Ожидаемый результат:
true false
Задание 3: in guard
Задача: Различи типы по свойствам.
Запустите код для проверки
Loading...
Ваш вывод:
Ожидаемый результат:
4 колеса 2 колеса
Проверь себя
- Какие встроенные type guards есть?
- Как создать пользовательский guard?
- Что делает assertion function?