TypeScript中使用对象扩展满足泛型联合类型的编译问题
TypeScript泛型函数返回联合类型编译错误问题
有一个包含共同字段type和fedBy的联合类型FeedAnimalParams,需要编写泛型函数feed:接收投喂者名称、动物类型Animal及对应动物的独有参数。通过泛型提取每种动物的独有参数类型UniqueAnimalParams,并定义返回类型FeedResult。函数调用时类型推断正常,但返回合并type、fedBy和独有参数的对象时出现编译错误,且需将结果传入不可修改的外部函数CantChangeSignature,调整返回类型后仍未解决问题。
联合类型定义
type FeedAnimalParams = | { type: 'Dog' fedBy: string bowl: true } | { type: 'Cat' fedBy: string fish: string } | { type: 'Bird' fedBy: string seed: string }
提取Animal类型
type Animal = FeedAnimalParams['type'] // type Animal = "Dog" | "Cat" | "Bird"
泛型提取独有参数
type UniqueAnimalParams<T extends Animal> = Omit<Extract<FeedAnimalParams, { type: T }>, 'type' | 'fedBy'> type FeedResult<T> = { message: string result: T }
函数实现及编译错误
function feed<T extends Animal>( byWhom: string, animalType: T, params: UniqueAnimalParams<T>, ): FeedResult<FeedAnimalParams> { return { message: `Fed by ${byWhom}`, result: { // 编译错误位置 type: animalType, fedBy: byWhom, ...params, }, } } // 外部不可修改函数 function CantChangeSignature(input: FeedAnimalParams){ console.log(input) }
函数调用示例
feed('Colin', 'Bird', { seed: 'Sunflower', }) feed('Joe', 'Dog', { bowl: true, })
尝试过的返回类型调整
FeedResult<FeedAnimalParams> // 也曾尝试此返回类型 FeedResult<Extract<FeedAnimalParams, {type:T}>>
解决方案
问题核心是TypeScript无法自动推断出合并后的对象严格匹配FeedAnimalParams的某个成员,以下两种方案可解决:
方案1:类型断言+精确返回类型
将合并对象断言为对应动物的参数类型,同时把函数返回类型设为精确的子类型(可兼容外部函数):
function feed<T extends Animal>( byWhom: string, animalType: T, params: UniqueAnimalParams<T>, ): FeedResult<Extract<FeedAnimalParams, { type: T }>> { return { message: `Fed by ${byWhom}`, result: { type: animalType, fedBy: byWhom, ...params, } as Extract<FeedAnimalParams, { type: T }>, } }
方案2:重构类型映射关系
通过定义动物类型与参数的映射,让TypeScript更清晰地识别类型关联:
// 定义动物类型到独有参数的映射 type AnimalParamMap = { Dog: { bowl: true }, Cat: { fish: string }, Bird: { seed: string } } // 基于映射重构联合类型 type FeedAnimalParams = { [K in keyof AnimalParamMap]: { type: K, fedBy: string } & AnimalParamMap[K] }[keyof AnimalParamMap] type Animal = keyof AnimalParamMap type UniqueAnimalParams<T extends Animal> = AnimalParamMap[T] function feed<T extends Animal>( byWhom: string, animalType: T, params: UniqueAnimalParams<T>, ): FeedResult<FeedAnimalParams> { return { message: `Fed by ${byWhom}`, result: { type: animalType, fedBy: byWhom, ...params, } as FeedAnimalParams, } }
兼容性验证
调整后的函数返回值可正常传入外部函数:
const birdResult = feed('Colin', 'Bird', { seed: 'Sunflower' }) CantChangeSignature(birdResult.result) // 无编译错误
内容的提问来源于stack exchange,提问作者colinwurtz
相关产品推荐
相关产品推荐

