Typescript中从类型参数获取类型补集解决泛型赋值报错问题
问题背景
这是项目实际问题的简化通用版本,项目需要给完全没有做类型设计、存在大量变更操作的老旧JS代码补充TS类型定义,且无权修改原有结构。
基础结构上可以挂载各类「扩展」,需要将扩展传入函数后在原基础上追加其他扩展,同时要保持所有逻辑为泛型。
初始问题
方案初步实现后Typescript抛出如下错误:
Type 'WrapperType' is not assignable to type 'Wrapper<ExtensionOf<WrapperType>>'. Type 'Wrapper<{}>' is not assignable to type 'Wrapper<ExtensionOf<WrapperType>>'. Type '{}' is not assignable to type 'ExtensionOf<WrapperType>'.
相关代码如下:
function fn<WrapperType extends Wrapper>(wrapper: WrapperType): Wrapper< ExtensionOf<WrapperType> // 此处类型推导异常,目标是在函数内追加更多扩展 > { return wrapper; // 此处抛出类型错误 } type BaseObj = { prop: number; }; type Wrapper< Extension = {} // 曾尝试将默认值替换为any > = { obj: Extension & BaseObj; // 曾尝试给Extension包裹Partial } // 由于Extension存在默认值,可以交换BaseObj和WrapperType['obj']的位置 type ExtensionOf<WrapperType extends Wrapper> = Complement<BaseObj, WrapperType['obj']>; type Complement<ExcludePropertiesFromThisType, Type extends ExcludePropertiesFromThisType> = Omit<Type, keyof ExcludePropertiesFromThisType>;
修改后出现的新问题
将函数修改为如下写法后出现更明确的类型错误:
function fn<WrapperType extends Wrapper>(wrapper: Wrapper): Wrapper<ExtensionOf<WrapperType>> { return { ...wrapper, }; }
对应报错:
Type '{ obj: BaseObj; }' is not assignable to type 'Wrapper<ExtensionOf<WrapperType>>'. Types of property 'obj' are incompatible. Type 'BaseObj' is not assignable to type 'ExtensionOf<WrapperType> & BaseObj'. Type 'BaseObj' is not assignable to type 'ExtensionOf<WrapperType>'.
更具体的报错为:Type 'BaseObj' is not assignable to type 'ExtensionOf<WrapperType> & BaseObj'.
预期实现效果
最终要达成的效果如下:
type WithOtherExtension = { yetAnotherProp: boolean } const myWrapper: Wrapper<{ otherProp: number }> = { obj: { prop: 1, otherProp: 2, }, }; const myModifiedWrapper: Wrapper<{ otherProp: number } & WithOtherExtension> = fn(myWrapper); console.log(myModifiedWrapper.obj.prop, myModifiedWrapper.obj.yetAnotherProp); function fn<WrapperType extends Wrapper>(wrapper: WrapperType): Wrapper< ExtensionOf<WrapperType> & WithOtherExtension > { // 不希望使用@ts-ignore忽略类型错误 const newWrapper: Wrapper<ExtensionOf<WrapperType> & WithOtherExtension> = wrapper; newWrapper.obj.yetAnotherProp = true; // 核心目标是支持该操作 return newWrapper; }
内容的提问来源于stack exchange,提问作者FloG
相关产品推荐
相关产品推荐

