简体   繁体   English

TypeScript 中是否可以使用编译时标记数字?

[英]Are compile-time tagged numbers possible in TypeScript?

As an example, I would like to create a Port type and a Seconds type, both thin wrappers around the number type, such that neither is assignable to the other.举个例子,我想创建一个Port类型和一个Seconds类型,这两个类型都是围绕number类型的薄包装,这样两者都不能分配给另一个。

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

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

We can get some semblance of type safety with unique symbol .我们可以通过unique symbol获得一些类型安全的外观。 Specifically, a field with declared type unique symbol will never compare compatible with another field of the same name, unless it comes from the same declaration.具体来说,声明类型unique symbol的字段永远不会与同名的另一个字段比较兼容,除非它来自相同的声明。 So we can tag our numbers with fake unique symbols to make them incomparable.所以我们可以用虚假的独特符号标记我们的数字,使它们无与伦比。

type Port = number & { readonly __tag: unique symbol };
type Seconds = number & { 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;

Now httpPort and oneMinute are mutually incompatible.现在httpPortoneMinute是互不兼容的。 If we try to compare them, we get something like this.如果我们尝试比较它们,我们会得到这样的结果。

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

Unfortunately, we can still do nonsense things like add two ports or a port or and a second together because Typescript will happily upcast either of them to number (that is how intersection types work, after all), but at least we can't pass a Port to a function expecting a Seconds anymore, or assign the variables incorrectly.不幸的是,我们仍然可以做一些无意义的事情,比如将两个端口或一个端口或一个第二个添加在一起,因为 Typescript 会很高兴地将它们中的任何一个向上转换为number (毕竟交集类型就是这样工作的),但至少我们不能通过一个Port到一个需要Seconds的函数,或者错误地分配变量。

Note that what you're trying to do is often referred to as the "newtype pattern", after the newtype keyword in Haskell (which exists for this exact purpose).请注意,您尝试执行的操作通常被称为“newtype 模式”,位于 Haskell 中的newtype关键字之后(正是为此目的而存在的)。 In particular, you can read more about its use in Typescript on this page (which is where I learned this little trick too).特别是,您可以在此页面上阅读有关它在 Typescript 中使用的更多信息(我也是在这里学到了这个小技巧)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM