TypeScript条件类型与可选属性兼容问题及实现等效类型的方法
TypeScript条件类型与可选属性的分发问题解决办法
在TypeScript中,条件类型与可选属性结合时,不会自动对条件分支进行分发。看下面的示例:
type A<X> = (X extends string ? { stringValue: X } : { otherValue: X }); type B<X> = A<X> & { optionalValue?: number } function func<X>(arg: B<X>) {} function test1<X>(arg: A<X>) { func(arg); } // 报错 function test2<X>(arg: A<X>) { func({ ...arg }); } // 报错 function test3<X>(arg: A<X>) { func({ ...arg, optionalValue: 42 }); } // 正常 function test4<X>(arg: A<X> & {}) { func({ ...arg }); } // 正常
test1和test2的错误提示为:Argument of type 'A<X>' is not assignable to parameter of type 'A<X> & { optionalValue?: number | undefined; }'.
当显式提供可选属性optionalValue时,test3可以正常运行;通过& {}强制低优先级类型推断时,test4也能正常运行。
我们预期B<X>的等效类型是:
X extends string ? { stringValue: X } & { optionalValue?: number } : { otherValue: X } & { optionalValue?: number }
实现方法
要让条件类型的每个分支都能和可选属性交叉,我们需要让B<X>成为分布式条件类型——也就是让类型参数X以“裸类型”的形式出现在条件判断中,触发TypeScript的分布式分发逻辑。
有两种常见实现方式:
方式1:直接重写B的条件逻辑
直接将可选属性的交叉逻辑嵌入到每个条件分支中,和预期结构一致:
type A<X> = X extends string ? { stringValue: X } : { otherValue: X }; type B<X> = X extends string ? { stringValue: X } & { optionalValue?: number } : { otherValue: X } & { optionalValue?: number };
方式2:利用分布式条件类型复用A的逻辑
如果不想重复A<X>的分支逻辑,可以通过infer触发分布式分发:
type A<X> = X extends string ? { stringValue: X } : { otherValue: X }; type B<X> = X extends infer T ? A<T> & { optionalValue?: number } : never;
这两种方式都能让B<X>的类型按条件分支分别与可选属性交叉,此时test1和test2都可以正常编译,无需额外处理。
内容的提问来源于stack exchange,提问作者motto
相关产品推荐
相关产品推荐

