如何在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
相关产品推荐
相关产品推荐

