TypeScript条件类型传枚举泛型时字段类型不符的解决方法
问题描述
我定义了泛型类型Type<T>,其中additionalField字段类型为T[]。为实现未传入泛型时该字段不存在的需求,我创建了默认泛型为void的ConditionalType<T = void>。
但当传入枚举MyEnum作为泛型时,ConditionalType<MyEnum>中的additionalField类型变成了MyEnum.TEST_1[] | MyEnum.TEST_2[],而非预期的MyEnum[];而Type<MyEnum>中的该字段类型则符合预期为MyEnum[]。
完整代码如下:
type ConditionalType<T = void> = { someField: string; } & (T extends void ? {} : { additionalField: T[]; }) type Type<T> = { someField: string; additionalField: T[]; } enum MyEnum { TEST_1 = "test_1", TEST_2 = "test_2" } const a: ConditionalType<MyEnum>;; a.additionalField // (property) additionalField: MyEnum.TEST_1[] | MyEnum.TEST_2[] // 需要改成 MyEnum[] const b: Type<MyEnum>;; b.additionalField; // (property) additionalField: MyEnum[] // 符合预期
请问如何让ConditionalType<MyEnum>中的additionalField类型变为MyEnum[]?为何ConditionalType<T = void>会出现这种情况?
解决方案
修改条件判断的写法,将T extends void改为[T] extends [void],避免触发分布式条件类型:
type ConditionalType<T = void> = { someField: string; } & ([T] extends [void] ? {} : { additionalField: T[]; })
修改后,ConditionalType<MyEnum>的additionalField类型会正确显示为MyEnum[]。
原因分析
问题出在分布式条件类型的特性上:
- 当条件类型中使用的是裸类型参数(比如直接写
T),且该参数是联合类型时,TypeScript会自动将条件判断拆分为联合类型的每个成员单独执行,最后合并结果。 MyEnum本质是MyEnum.TEST_1 | MyEnum.TEST_2的联合类型,原代码中T extends void会分别检查两个枚举成员,两者都不满足extends void,因此生成{ additionalField: MyEnum.TEST_1[] } | { additionalField: MyEnum.TEST_2[] },对应字段类型就是MyEnum.TEST_1[] | MyEnum.TEST_2[]。- 而
Type<T>直接定义additionalField: T[],不会触发分布式展开,因此MyEnum[]是正常的枚举数组类型。
将T包裹在元组[T]中后,它不再是裸类型参数,分布式条件类型的逻辑不会触发,TypeScript会把MyEnum作为一个整体进行判断,从而得到正确的additionalField: MyEnum[]。
内容的提问来源于stack exchange,提问作者Artheg
相关产品推荐
相关产品推荐

