如何处理TypeScript中同名同构不同命名子类型的联合类型问题?
处理GraphQL自动生成的相似类型兼容问题
我有两个GraphQL自动生成的类型dogType和catType,命名不同但结构高度相似,子类型dogNumLegsType和catNumLegsType的取值范围完全一致,但TypeScript判定它们是不同类型。现在要写一个兼容两种类型的函数,基于numLegs属性执行逻辑,访问tail没问题,但访问numLegs会触发类型冲突,请问怎么解决?
类型定义如下:
type dogType = { __typeName: 'dogType', doggoId: string, numLegs: dogNumLegsType, tail: boolean } type dogNumLegsType = 1 | 2 | 3 | 4; type catType = { __typeName: 'catType', kittyId: string, numLegs: catNumLegsType, tail: boolean } type catNumLegsType = 1 | 2 | 3 | 4;
解决方案
定义通用共享类型
先提取两者共有的属性类型,创建一个通用的Pet接口。因为TypeScript是结构类型系统,dogType和catType会自动兼容这个接口:type Pet = { numLegs: 1 | 2 | 3 | 4; tail: boolean; }; function handlePet(pet: Pet) { if (pet.numLegs === 4) { console.log("这只宠物有四条腿"); } console.log(`是否有尾巴:${pet.tail}`); } // 直接传入dog或cat实例即可 const myDog: dogType = { __typeName: 'dogType', doggoId: 'd1', numLegs: 4, tail: true }; const myCat: catType = { __typeName: 'catType', kittyId: 'c1', numLegs: 3, tail: false }; handlePet(myDog); handlePet(myCat);用类型断言快速兼容
如果不想额外定义类型,可在函数内部把numLegs断言为通用联合类型,简单直接:function handleAnimal(animal: dogType | catType) { const numLegs = animal.numLegs as 1 | 2 | 3 | 4; switch (numLegs) { case 1: console.log("只有一条腿"); break; case 4: console.log("四条腿健全"); break; } }用条件类型提取共享子类型
通过TypeScript条件类型自动提取numLegs的类型,避免手动重复编写联合类型:// 提取任意类型中numLegs的类型 type ExtractNumLegs<T> = T extends { numLegs: infer L } ? L : never; // 从dogType中提取出numLegs类型(和catType的numLegs完全一致) type SharedLegsType = ExtractNumLegs<dogType>; function handleAnimal(animal: dogType | catType) { const numLegs: SharedLegsType = animal.numLegs; // 基于numLegs的逻辑处理 }
关于类型匹配规则的说明
TypeScript本身就是结构类型系统,只会关注类型的结构而非名称。dogNumLegsType和catNumLegsType在结构上完全兼容,TypeScript允许它们互相赋值。出现冲突的原因是当参数为dogType | catType联合类型时,numLegs的类型会被推断为dogNumLegsType | catNumLegsType,如果操作需要更明确的单一类型,就会触发报错。上面的方法都能解决这个问题,不需要修改TypeScript的底层匹配规则。
内容的提问来源于stack exchange,提问作者NegativeFriction
相关产品推荐
相关产品推荐

