如何实现泛型判别式联合的Case类型?能否无需declare获取type类型?
解答你的TypeScript泛型判别式联合问题
好的,咱们来逐个解决你的两个问题:
一、无需额外declare语句获取type属性的可能取值
你完全可以直接通过索引访问联合类型的属性来获取所有type的可能值,不需要额外声明变量。这种方式更简洁直接:
interface IFoo { type: "foo"; foo: number; } interface IBar { type: "bar"; bar: number; } interface IBaz { type: "baz"; baz: number; } type IObject = IFoo | IBar | IBaz; // 直接索引IObject的type属性,得到联合类型 "foo" | "bar" | "baz" type ObjectType = IObject["type"];
原理说明
在TypeScript中,当你对联合类型使用索引访问(比如T["key"]),编译器会自动遍历联合类型的每个成员,收集对应key的属性值,最终返回这些值的联合类型,刚好完美匹配你想要的ObjectType。
二、实现泛型Case类型及对应的filter函数
这个需求完全可行!我们可以通过条件类型实现Case泛型,再配合类型谓词让filter函数返回正确的子类型数组。
1. 定义Case泛型
// 从联合类型T中筛选出type属性等于K的成员 type Case<T, K extends string> = T extends { type: K } ? T : never;
这个条件类型的逻辑是:遍历联合类型T的每个成员,检查该成员是否包含type: K的属性,如果是则保留该类型,否则返回never(会被联合类型自动忽略)。
2. 实现类型安全的filter函数
我们可以用类型谓词(o is Case<IObject, Type>)来让TypeScript准确识别筛选后的类型:
function filter<Type extends ObjectType>( objects: IObject[], type: Type, ): Case<IObject, Type>[] { // 用类型谓词告诉TS:当回调返回true时,o的类型是Case<IObject, Type> return objects.filter((o): o is Case<IObject, Type> => o.type === type); }
3. 使用示例
const objects: IObject[] = [ { type: "foo", foo: 1 }, { type: "bar", bar: 2 }, { type: "baz", baz: 3 }, ]; const fooObjects = filter(objects, "foo"); // fooObjects的类型自动推导为IFoo[],可以直接访问foo属性 console.log(fooObjects[0].foo); // 正常运行 const barObjects = filter(objects, "bar"); // barObjects的类型自动推导为IBar[]
这样你的filter函数就能根据传入的type参数,返回对应子类型的数组,完全符合预期。
内容的提问来源于stack exchange,提问作者mikea
相关产品推荐
相关产品推荐

