#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.