TS编译器对涉及枚举品牌的联合类型不满意(标称类型)

时间:2019-04-05 08:38:07

标签: typescript types union-types

我正在使用一个枚举来实现名义上的打字(例如TypeScript Deep Dive书中所建议的):

enum ExampleIdBrand {}
export type ExampleId = ExampleIdBrand & string
const exampleId: ExampleId = '42' as ExampleId

const m1 = (e: ExampleId) => e.toUpperCase()
m1(exampleId) // ✅

到目前为止,一切正常。但是,如果我更改方法以接受(更广泛的)联合类型,则编译器将不再接受我的exampleId

const m2 = (e: ExampleId | 'whatever') => e.toUpperCase()
m2('whatever') // ✅
m2(exampleId) //  Does not compile

为什么最后一行编译不正确? (TS 3.3.4000)

2 个答案:

答案 0 :(得分:1)

在TypeScript中,枚举可以是数字或字符串。数字没有.toUpperCase()方法。

您的示例应该可以正常工作,因为枚举被缩小为字符串类型。

一种解决方法是:

enum ExampleIdBrand {}
export type ExampleId = ExampleIdBrand;
const exampleId: ExampleId = '42';

const m1 = (e: ExampleId) => e.toString().toUpperCase();
m1(exampleId);

const m2 = (e: ExampleId | 'whatever') => e.toString().toUpperCase();
m2('whatever'); // ✅
m2(exampleId); // ✅

答案 1 :(得分:1)

交集为空集(即没有值可以是交集的实例)发生的事情已经改变。尽管会一直寻找,但我找不到真正的文档,但是在某些情况下,此类交叉点会崩溃到永远。在这种情况下ExampleId | 'whatever' = never | 'whatever' = 'whatever'

const m2 = (e: ExampleId | 'whatever') => e.toUpperCase()
type x =  Parameters<typeof m2>[0] //  'whatever'

要保持ExampleId的名义性质,我们可以添加属性:

enum ExampleIdBrand {}
export type ExampleId = { __brand: ExampleIdBrand } & string
const exampleId: ExampleId = '42' as ExampleId

const m1 = (e: ExampleId | "whatever") => e.toUpperCase()
m1(exampleId) // ✅
m1("whatever")// ✅

或者,如果我们想很好地隐藏该成员,则可以使用带有私有字段的类的交集:

enum ExampleIdBrand { }
class Brand<T> { private __brand: T}
export type ExampleId = Brand<ExampleIdBrand> & string
const exampleId: ExampleId = '42' as ExampleId

const m1 = (e: ExampleId | "whatever") => e.toUpperCase()
m1(exampleId) // ✅
m1("whatever")// ✅

或删除枚举并使用此class ExampleIdBrand { private __brand!: any}