0

我在 Typescript 中看到了许多不同的方式来处理名义类型,但它们似乎都在某些方面有所不足。我希望保留所有这些属性:

  1. 必须有明确的(不一定简洁,但如果是的话,但加分)编译器错误消息传达哪些不透明类型,例如Type 'GBP' is not assignable to type 'JPY'.
  2. 必须是真正唯一的以避免意外匹配相似的不透明类型,即没有__tag__键,必须使用unique symbol.
  3. 必须能够拥有采用不透明类型共享相同底层原始类型的安全泛型函数,例如<A>(Opaque<number, A>) => Opaque<number, A>.

语法上干净的界面可以获得更多奖励积分,但我知道这是主观的。

4

1 回答 1

1

这是我发现的最好的方法:

namespace Unique {
  export declare const Newtype: unique symbol
  export declare const JPY: unique symbol
  export declare const GBP: unique symbol
}

type Newtype<A, B extends symbol> = A & { readonly [Unique.Newtype]: B }

type JPY = Newtype<number, typeof Unique.JPY>
type GBP = Newtype<number, typeof Unique.GBP>

const test: <A extends symbol>(a: Newtype<number, A>, b: Newtype<number, A>) => Newtype<number, A>
  = (a, b) => a + b as any // massage the type checker a bit

// fails
test(10 as GBP, 10)
test(10 as GBP, 10 as JPY)

// passes
test(10 as GBP, 10 as GBP)
test(10 as JPY, 10 as JPY)
  1. 成立,但这里没有奖励积分,因为您最终会收到一些包含文件路径的非常讨厌的错误消息(现场示例,请参阅“错误”)Newtype<number, typeof import("file:///input").JPY>:。我希望有一种涉及接口扩展或类似的方法来使这个更干净。

  2. 成立,因为两者Unique.Newtype都是Unique.JPYs unique symbol

  3. 成立,因为我们可以使用结构Newtype来确保类型是肯定的Newtype,因为它是根据Unique.Newtypewhich is定义的unique symbol

于 2020-05-17T17:47:17.643 回答