You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.26 16:06:03