如何利用TypeScript类型系统创建操作集合的强类型过滤函数
实现强类型类式过滤函数
当然可以实现!利用TypeScript的条件类型、infer关键字以及联合类型的特性,完全能打造出你想要的强类型过滤函数。下面是针对你需求的具体实现方案:
1. 定义核心辅助类型
首先我们把所有子类的联合类型抽出来(你提到可以自动生成代码,所以不用担心冗余),然后定义一个用来筛选符合属性值条件的辅助类型:
type ClassNames = 'B' | 'C' | 'D'; declare class A { protected constructor(); className: ClassNames; attr1: string; } declare class B extends A { private constructor(); className: 'B'; attr2: string; attr4: number; } declare class C extends A { private constructor(); className: 'C'; attr3: number; attr4: string; } declare class D extends A { private constructor(); className: 'D'; attr4: string | number; } // 定义所有子类的联合类型,方便后续复用 type AllSubclasses = B | C | D; // 核心辅助类型:从联合类型中筛选出指定属性等于目标值的类型 type FilterByProperty< PropName extends keyof AllSubclasses, PropValue, T extends A | AllSubclasses = AllSubclasses > = T extends infer U ? // 如果当前类型是子类,直接检查属性值 U extends AllSubclasses ? U[PropName] extends PropValue ? U : never : // 如果当前类型是基类A,自动替换为所有子类进行筛选 FilterByProperty<PropName, PropValue, AllSubclasses> : never;
2. 修正Filter类的类型声明
接下来重写Filter类的has方法,利用上面的辅助类型实现正确的类型过滤:
declare class Filter<T extends A | AllSubclasses = AllSubclasses> { // has方法:接收属性名和属性值,返回过滤后的Filter实例 has<U extends keyof AllSubclasses, V extends AllSubclasses[U]>( propName: U, propVal: V ): Filter<FilterByProperty<U, V, T>>; all(): T[]; }
3. 验证示例场景
现在测试你给出的示例,完全符合预期:
let g = new Filter<A>(); let x = g.has('className', 'B'); let y = g.has('attr4', 'whatever'); type X = typeof x; // 类型为Filter<B>,符合预期 type Y = typeof y; // 类型为Filter<C | D>,符合预期
关键知识点说明
- 你之前的
has方法错误地使用了交集类型T & {[K in U]: V},这是给类型添加属性约束,而我们需要的是从联合类型中筛选出符合条件的成员,所以条件类型+infer才是正确方向。 FilterByProperty中的infer U用来遍历联合类型中的每个成员,逐个检查属性值是否匹配,不匹配的成员会被转换成never,联合类型会自动忽略never成员。- 考虑到你初始实例可能传入基类
A,我们在辅助类型中做了兼容,当T是A时会自动切换为所有子类进行筛选。
内容的提问来源于stack exchange,提问作者K.Steff
相关产品推荐
相关产品推荐

