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

如何在TypeScript中按成员类型过滤对象并移除无关键?

按成员类型过滤TypeScript对象类型的正确实现

你需要实现一个TypeScript类型工具FilterByType,目标是仅保留对象中属性类型完全匹配指定类型的键值对,而非将不匹配的键设为never。当前的实现虽然能在赋值时报错,但无法彻底移除不匹配的键,导致keyof仍能识别这些无效键。


现有实现及问题

第一种实现:

type FilterByType<T, M, K extends keyof T = keyof T> = {
    [P in K]: T[P] extends M ?
      M extends T[P] ?
        T[P]
      : never
    : never;
};

测试示例:

type Example = FilterByType<{a: number; b: string}, number>;

// 赋值时b会报错,这部分符合预期
let t: Example = {
  a: 1,
  b: '2', // 错误:类型"string"不能赋值给类型"never"
};

// 问题:此处未报错,但b并非有效键
let k: (keyof Example)[] = ['a', 'b'];

此时生成的Example类型为:

type Example = {
  a: number;
  b: never;
};

你尝试的第二种实现也未解决问题:

type FilterByType<T, M, K extends keyof T = keyof T> = {
  [P in Extract<
    K,
    T[K] extends M ?
      M extends T[K] ?
        K
      : never
    : never
  >]: T[P];
};

正确实现

核心思路是先筛选出所有属性类型完全匹配M的键,再基于这些键构建新类型。需要注意用单个键的属性类型T[P]做判断,而非批量的T[K]:

type FilterByType<T, M> = {
  [P in keyof T as T[P] extends M ? (M extends T[P] ? P : never) : never]: T[P];
};

验证效果

用同样的测试示例验证:

type Example = FilterByType<{a: number; b: string}, number>;

// 此时Example的类型为 { a: number }
let t: Example = {
  a: 1,
  // 若添加b会直接报错:对象文字只能指定已知属性,"b"不在类型"Example"中
};

// 此处会报错:类型""b""不能赋值给类型""a""
let k: (keyof Example)[] = ['a', 'b'];

代码解释

  • as关键字用于映射过滤:遍历keyof T时,对每个键P做条件判断,只保留符合要求的键
  • T[P] extends M ? (M extends T[P] ? P : never) : never:确保T[P]和M互相兼容(即类型完全匹配,避免子类型/父类型误判),符合条件的键保留,否则被过滤
  • 最终生成的类型仅包含有效键值对,彻底移除无效键

内容的提问来源于stack exchange,提问作者voodooattack

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 17:05:03