【问题标题】:Are compile-time tagged numbers possible in TypeScript?TypeScript 中是否可以使用编译时标记的数字?
【发布时间】:2021-01-14 11:32:34
【问题描述】:

例如,我想创建一个Port 类型和一个Seconds 类型,这两个类型都是围绕number 类型的薄包装,这样两者都不能分配给另一个。

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

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

【问题讨论】:

  • 我认为使用不同的对象是你最好的选择。

标签: typescript types


【解决方案1】:

我们可以使用unique symbol 获得一些类型安全的表象。具体来说,声明类型为unique symbol 的字段永远不会与另一个同名字段比较兼容,除非它来自同一个声明。所以我们可以用伪造的唯一符号标记我们的数字,使它们无法比拟。

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;

现在httpPortoneMinute 相互不兼容。如果我们尝试比较它们,我们会得到类似的结果。

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(毕竟这就是交集类型的工作方式),但至少我们不能再将Port 传递给期望Seconds 的函数,或者错误地分配变量。

请注意,在 Haskell 中的 newtype 关键字之后(正是为此目的而存在),您尝试执行的操作通常被称为“新类型模式”。特别是,您可以阅读更多关于它在 Typescript on this page 中的使用(我也是从那里学到了这个小技巧)。

【讨论】:

  • 使用联合而不是交集有什么缺点吗?您保持不同标记整数之间的不兼容性,但您可以免费获得来自number 的强制转换。
猜你喜欢
  • 1970-01-01
  • 2011-06-15
  • 2012-09-22
  • 1970-01-01
  • 2019-01-08
  • 1970-01-01
  • 1970-01-01
  • 2022-01-12
相关资源
最近更新 更多