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



我正在使用枚举来实现名义类型(例如在TypeScript Deep Dive book中建议(:

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(

在 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); // ✅

集的交集(即没有值可以成为交集的实例(会发生什么是已经改变的事情。我真的找不到文档,虽然我会继续寻找,但在某些情况下,这样的交叉点会崩溃到永远不会。在这种情况下,我们看到了这一点,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}

最新更新