TypeScript如何泛型省略所有指定类型的属性(如List类型属性)?
核心问题根源
- 你之前实现的
WithoutList类型并没有真正“删除匹配类型的属性”,只是把匹配属性的值类型替换成了never,但属性键本身完全和原类型一致。 - 举个最简验证:
这就导致type Demo = { a: string, b: never } // keyof Demo 的实际取值是 'a' | 'b',和带真实值类型的对象键集合没有区别keyof WithoutList<Student>和原生keyof Student完全一致,courses这类本应被过滤的键依然会出现在可选参数列表中,类型约束自然失效。
正确实现方案
1. 实现真正按属性类型过滤的泛型
要实现“属性类型匹配List就直接剔除”的逻辑,分两种场景适配不同TS版本:
高版本TS(4.1+,支持键重映射语法)
利用映射类型的as重映射能力,在遍历键的阶段就把匹配类型的键返回never,从类型层面彻底删除对应成员:
// 通用工具:从源类型T中排除所有属性类型匹配FilterType的键 type OmitByType<T, FilterType> = { [K in keyof T as T[K] extends FilterType ? never : K]: T[K] } // 专门适配排除List类型属性的版本 type WithoutList<T> = OmitByType<T, List<any>>
- 对
Student应用该类型后,会生成去掉courses的结构:{ firstName: string, lastName: string, age: number, gender: Gender } - 对
Program应用该类型后,会剔除所有List类型的属性(errors/successes/warnings),最终只剩{ name: string },完全符合预期。
低版本TS兼容写法
如果项目TS版本低于4.1,不支持as键重映射,可以先提取所有需要剔除的键联合类型,再用内置Omit实现等价效果:
type WithoutList<T> = Omit< T, { [K in keyof T]: T[K] extends List<any> ? K : never }[keyof T] >
2. 调整select函数的类型约束
将之前select的泛型绑定到修正后的WithoutList类型上,类型校验就会正常生效:
const select = <T, K extends keyof WithoutList<T>>(arg: T, ...keys: K[]) => { return null! }
调整后:
- 调用
select(s1, 'courses')会直接触发TS类型报错,提示'courses'不是合法参数 - 传入非List类型的属性,比如
select(s1, 'firstName', 'age')就可以正常通过类型校验
内容的提问来源于stack exchange,提问作者Steven Soekha
相关产品推荐
相关产品推荐

