如何在TypeScript联合类型中替换fn方法的参数类型?
替换联合类型中函数的参数类型,保留原有联合结构
库提供的类型定义
// given typings of library type t1 = string type t2 = number type t3 = { [key: string]: number | string | boolean | Array<string | number> | undefined } interface i0 { aa: t1 fn?: (arg: t3) => boolean } interface i1 extends i0 { ba: t2, bb: t2 } interface i2 extends i0 { ca: t2, cb: t2 } type union = i1 | i2
自定义类型及问题示例
// my typings type t4 = { prop1: string, prop2: number } type myfn<T> = { fn?: ((arg: T) => boolean) } type mytype<T> = myfn<T> | Omit<union, 'fn'> type myNonUnionType<T> = myfn<T> | Omit<i1, 'fn'> // implementation examples let obj1: union = { aa: 'hello', ba: 3, bb: 4, fn: (arg) => arg.prop1 === arg.prop2.toString() // error: possible undefined } let obj2: mytype<t4> = { aa: 'hello', ba: 2, // error: ba does not exist bb: 3, fn: (arg) => arg.prop1 === arg.prop2.toString() } let obj3: mytype<t4> = { aa: 'hello', ca: 2, // error: ca does not exist cb: 3, fn: (arg) => arg.prop1 === arg.prop2.toString() } let obj4: myNonUnionType<t4> = { // works, but only without union aa: 'hello', ba: 2, bb: 3, fn: (arg) => arg.prop1 === arg.prop2.toString() }
问题原因
你定义的mytype<T>是把「仅包含自定义fn的类型」和「移除了fn的原联合成员」做联合。但当你编写同时拥有原联合成员属性(比如ba/ca)和自定义fn的对象时,这个对象既不属于myfn<T>(多了额外属性),也不属于Omit<union, 'fn'>(多了fn属性),导致TypeScript判定属性不存在。
解决方案
不需要拆分fn为独立分支,直接给原联合类型的每个成员单独替换fn的参数类型即可,用工具类型实现:
// 工具类型:替换目标类型中fn的参数为指定类型 type ReplaceFnParam<OriginalType, NewParam> = Omit<OriginalType, 'fn'> & { fn?: (arg: NewParam) => boolean } // 对原联合类型的每个成员应用参数替换 type mytype<T> = ReplaceFnParam<union, T>
验证效果
// 正常兼容i1结构+自定义fn参数 let obj2Fix: mytype<t4> = { aa: 'hello', ba: 2, bb: 3, fn: (arg) => arg.prop1 === arg.prop2.toString() // 无错误,arg类型为t4 } // 正常兼容i2结构+自定义fn参数 let obj3Fix: mytype<t4> = { aa: 'hello', ca: 2, cb: 3, fn: (arg) => arg.prop1 === arg.prop2.toString() // 无错误,arg类型为t4 } // 也支持省略fn的场景 let obj5: mytype<t4> = { aa: 'hello', ba: 5, bb: 6 }
这个方案的核心是保留原联合类型的结构,只针对每个成员的fn属性做参数类型替换,完美解决联合类型兼容问题。
内容的提问来源于stack exchange,提问作者dnmeid
相关产品推荐
相关产品推荐

