TypeScript中如何自动跳过不属于目标类型的属性?
首先得明确一个关键事实:TypeScript的类型系统完全是编译时的,运行时不会自动修改对象结构。所以直接写const point: Point2D = response只是告诉编译器“把response当作Point2D类型处理”,但运行时point依然会包含所有外来属性(foreign1、foreign2这些)——TypeScript不会帮你做任何裁剪。
要实现运行时自动保留类型定义内的属性、丢弃其他属性,你需要写一段运行时逻辑来处理。这里有几种实用的方案:
方案1:通用Pick工具函数
这是最灵活的方案,适合任意类型的属性提取。我们可以写一个通用函数,传入原始对象和需要保留的属性键,返回仅包含指定属性的新对象:
// 先定义你的类型 type Point2D = { x: number, y: number }; // 通用Pick函数 function pick<T extends object, K extends keyof T>(obj: T, allowedKeys: K[]): Pick<T, K> { const result = {} as Pick<T, K>; allowedKeys.forEach(key => { // 确保对象确实有这个属性(避免隐式继承的属性) if (obj.hasOwnProperty(key)) { result[key] = obj[key]; } }); return result; } // 使用示例 const response = { x: 1.2, y: 3.4, foreign1: 'value', foreign2: 'value' }; const point: Point2D = pick(response, ['x', 'y']); // 验证:运行时point只包含x和y console.log(point); // { x: 1.2, y: 3.4 }
这个函数的好处是复用性极强,不管你有什么类型,只要传入对应的属性键数组就能提取需要的属性。
方案2:Object.fromEntries + 过滤(简单场景)
如果只是临时处理某个对象,不想写通用函数,可以用Object.fromEntries结合数组过滤快速实现:
type Point2D = { x: number, y: number }; const response = { x: 1.2, y: 3.4, foreign1: 'value', foreign2: 'value' }; const point: Point2D = Object.fromEntries( Object.entries(response).filter(([key]) => ['x', 'y'].includes(key)) ) as Point2D;
这种写法更简洁,但复用性不如通用函数,适合一次性的简单场景。
为什么不能让TypeScript自动做这件事?
因为TypeScript的类型信息在编译成JavaScript后就完全消失了——运行时根本不知道Point2D这个类型的存在,自然无法自动判断哪些属性需要保留。所以必须在代码中显式指定要保留的属性(不管是通过函数参数还是过滤数组)。
进阶:自动获取类型的属性键(可选)
如果你觉得手动写属性键太麻烦,想让工具帮你自动生成,可以使用ts-transformer-keys这类TypeScript编译时转换器。它能在编译阶段把类型的键转换成运行时数组,但需要额外配置TypeScript的编译选项,适合大型项目或者有大量这类需求的场景。
不过对于大多数普通场景,手动指定属性键的方案已经足够简单可靠了。
内容的提问来源于stack exchange,提问作者QooBooS

