Перейти к основному содержимому
Модуль 5 · Урок 1 из 29/14 в курсе~15 min
Уроки модуля (1/2)

Тип Охранники

Сужение типов — одна из наиболее важных концепций TypeScript. Однако зачастую стандартных средств защиты типов, таких как typeof или instanceof, недостаточно для сложных пользовательских объектов. Здесь на помощь приходят Защитники пользовательского типа.

Стандартный тип защиты

Начнем с подведения итогов того, как TypeScript сужает типы с помощью стандартных операторов JavaScript:

TS
function processInput(val: string | number) {
  if (typeof val === 'string') {
    // Here 'val' is of type string
    console.log(val.toUpperCase());
  } else {
    // Here 'val' is of type number
    console.log(val.toFixed(2));
  }
}

Пользовательские типы защиты (оператор is)

Чтобы определить защиту пользовательского типа, мы создаем функцию, которая возвращает предикат типа в формате parameterName is Type вместо стандартного логического возвращаемого типа.

Функция должна возвращать логическое значение (true или false). Если он возвращает true, TypeScript будет знать, что переданный параметр имеет указанный тип.

TS
interface Cat {
  name: string;
  meow(): void;
}

interface Dog {
  name: string;
  bark(): void;
}

// This is a custom type guard
function isCat(animal: Cat | Dog): animal is Cat {
  return (animal as Cat).meow !== undefined;
}

function makeNoise(pet: Cat | Dog) {
  if (isCat(pet)) {
    // Here TypeScript knows 'pet' is a Cat
    pet.meow();
  } else {
    // Here TypeScript knows 'pet' is a Dog
    pet.bark();
  }
}

Безопасность и литье (as против типовых ограждений)

Приведение типов (например, val as Cat) заставляет компилятор доверять разработчику без какой-либо реальной проверки во время выполнения. Если объект времени выполнения не соответствует ожиданиям, код автоматически выдаст ошибку или выдаст исключения.

С другой стороны, специальные средства защиты типов выполняют надежную и динамическую проверку во время выполнения, безопасно и точно информируя компилятор TypeScript о фактическом типе переменной:

TS
function processInput(input: unknown) {
  // unsafe casting: could crash if input does not have the split method
  // const str = input as string;
  // console.log(str.split(' '));

  // safe guard
  if (isString(input)) {
    console.log(input.split(' ')); // 100% Safe!
  }
}

Попробуйте сами

Упражнение 1: Защита струнного типа

Упражнение#ts.m5.l1.e1
Попыток: 0Загрузка…

Создайте простую функцию с именем isString, которая действует как защита пользовательского типа и проверяет, является ли неизвестное значение строкой.

Загрузка редактора…
Показать подсказку

Тип возвращаемого значения функции должен быть val — строка, и вам следует использовать typeof, чтобы проверить, равен ли он «строке».

Решение доступно после 3 попыток

Упражнение 2. Защита типов премиум-пользователей

Упражнение#ts.m5.l1.e2
Попыток: 0Загрузка…

Учитывая типы User и PremiumUser, напишите функцию защиты типа isPremiumUser(user: User): user is PremiumUser, которая проверяет, имеет ли пользователь роль «премиум».

Загрузка редактора…
Показать подсказку

Определите подпись как функцию isPremiumUser(user: User): пользователь — PremiumUser и сравните user.role с «premium».

Решение доступно после 3 попыток

Упражнение 3. Проверка пользовательского объекта ошибки

Упражнение#ts.m5.l1.e3
Попыток: 0Загрузка…

Реализуйте функцию isCustomError(err:known): err — это функция CustomError, которая проверяет, является ли неизвестное значение ненулевым объектом CustomError, содержащим ключ «code».

Загрузка редактора…
Показать подсказку

Сначала проверьте, является ли typeof err «объектом», а не нулевым, затем используйте оператор «in», чтобы проверить свойство «code».

Решение доступно после 3 попыток

Упражнение 4. Защита типа администратора

Упражнение#ts.m5.l1.e4
Попыток: 0Загрузка…

Имея два интерфейса User (со свойством role: string) и Admin (расширяющим User и имеющим свойство adminToken: string), напишите функцию защиты типа с именем isAdmin, которая принимает пользователя типа User и возвращает предикат типа user — Admin. Охранник должен проверить, равна ли роль пользователя «admin».

Загрузка редактора…
Показать подсказку

Определите подпись как функцию isAdmin(user: User): пользователь является администратором и проверьте, имеет ли user.role === 'admin'.

Решение доступно после 3 попыток