Возможны ли номера с метками во время компиляции в TypeScript?

#typescript #types

#typescript #типы

Вопрос:

В качестве примера я хотел бы создать Port type и Seconds type, оба тонкие оболочки вокруг number типа, чтобы ни один из них не мог быть назначен другому.

 let httpPort: Port = 80;
let oneMinute: Seconds = 60;

httpPort = oneMinute; // type error
oneMinute = httpPort; // type error
  

Комментарии:

1. Я думаю, что использование разных объектов — ваш лучший выбор.

Ответ №1:

Мы можем получить некоторое подобие безопасности типов с unique symbol помощью . В частности, поле с объявленным типом unique symbol никогда не будет сопоставимо с другим полем с тем же именем, если только оно не взято из того же объявления. Таким образом, мы можем помечать наши числа поддельными уникальными символами, чтобы сделать их несравнимыми.

 type Port = number amp; { readonly __tag: unique symbol };
type Seconds = number amp; { readonly __tag: unique symbol };

// Note that we do have to explicitly cast the numbers, as we're
// technically lying to the type system to get this behavior.
let httpPort = 80 as Port;
let oneMinute = 60 as Seconds;
  

Теперь httpPort и oneMinute взаимно несовместимы. Если мы попытаемся сравнить их, мы получим что-то вроде этого.

 file.ts:8:1 - error TS2322: Type 'Seconds' is not assignable to type 'Port'.
  Type 'Seconds' is not assignable to type '{ readonly __tag: unique symbol; }'.
    Types of property '__tag' are incompatible.
      Type 'typeof __tag' is not assignable to type 'typeof __tag'. Two different types with this name exist, but they are unrelated.

8 httpPort = oneMinute; // type error
  

К сожалению, мы все еще можем делать бессмысленные вещи, такие как добавление двух портов или порта или и второго вместе, потому что Typescript с радостью передаст любой из них number (в конце концов, так работают типы пересечений), но, по крайней мере, мы больше не можем передавать a Port функции, ожидающей a Seconds , или присваивать переменныенеправильно.

Обратите внимание, что то, что вы пытаетесь сделать, часто называют «шаблоном newtype» после newtype ключевого слова в Haskell (которое существует именно для этой цели). В частности, вы можете прочитать больше о его использовании в Typescript на этой странице (где я тоже научился этому маленькому трюку).

Комментарии:

1. Есть ли недостатки в использовании объединения вместо пересечения? Вы сохраняете несовместимость между различными целыми числами с тегами, но получаете приведения из number for free.