ПрограммированиеTypeScript разработчик

Что такое Literal Types в TypeScript, и для чего они используются? Как с помощью них можно реализовать строгие ограничения на значения переменных и какие ловушки бывают при их применении?

Проходите собеседования с ИИ помощником Hintsage

Ответ

Literal Types позволяют ограничить возможные значения переменной только определёнными строгими константами, а не просто общим типом (например, не просто число, а число 5 или строка "yes").

Это полезно для создания API с фиксированными параметрами, статуса и т.п.

type Direction = 'left' | 'right' | 'up' | 'down'; function move(dir: Direction) { // ... } move('left'); // OK move('top'); // Ошибка компиляции!

Также работают с числами, boolean и даже целыми структурами (tuple literal type):

type WeekDay = 1 | 2 | 3 | 4 | 5 | 6 | 7; const day: WeekDay = 6; // OK

Ограничения и нюансы:

  • К типам-литералам нельзя неявно приводить значения (например, нельзя присвоить переменной с типом 'left' | 'right' строку из пользовательского ввода без проверки).
  • При работе с константами и let-переменными важно помнить о типе вывода:
const d = 'left'; // имеет тип 'left' (Literal) let e = 'left'; // имеет тип string (обычный)

Вопрос с подвохом

Вопрос: Какой тип получит переменная, если определить её как const x = "yes"; — и можно ли потом присвоить ей другое строковое значение?

Ответ:

  • Если объявить const x = "yes"; — x будет иметь тип "yes" (literal type), и ей нельзя будет присвоить вообще никакое другое значение, кроме 'yes' (и изменить нельзя вообще, потому что const).
  • Если объявить let x = "yes";, то x будет типизирован как string, и можно будет присваивать любые строки.
const x = 'yes'; // x: 'yes' let y = 'yes'; // y: string

Примеры реальных ошибок из-за незнания тонкостей темы.


История

В проекте для статусов задач использовался enum, но разработчик заменил его на string. В результате API начало принимать любые строки в качестве статуса, что породило множество багов при развитии продукта на проде, потому что был утрачен контроль.


История

Разработчик пытался использовать литеральные типы валидации данных, но присваивал параметры из поля формы напрямую — TS позволил это сделать, т.к. тип поля input был string, а не литерал (например, "ok" | "fail"), так как input-значения не были проверены. В итоге в рантайме появлялись значения не из множества допустимых.


История

Во время написания тестов для функции, которая принимала литеральные значения, автоматически сгенерированный тест случайно подал неожиданный строковой параметр, тесты не проходили. Позже выяснилось, что типизация была ослаблена из-за невнимания к выводу типов при let-объявлении, и это не отловил компилятор.