TypeScript如何从子接口实例提取父接口属性生成新实例
解决方案
有多种更高效的实现方案,覆盖原生实现和第三方库实现两类,且可以结合TypeScript内置工具类型保证类型安全:
1 原生TypeScript/JavaScript实现
1.1 解构赋值剔除多余属性
适合Driver独有属性较少的场景,无需额外工具函数,运行时会自动剥离多余属性,TS也能自动推导得到符合Person接口的类型:
// 把Driver独有的属性解构出来,剩余属性自动组成Person对象 const { driverLicense, carModel, ...johnAsPerson } = johnAsDriver;
1.2 结合内置工具类型Pick实现通用属性提取
可以自己实现一个轻量的pick函数,用到TS内置的Pick<Type, Keys>工具类型,同时保证编译期类型校验和运行时属性正确:
// 通用属性提取函数 function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> { return Object.fromEntries( keys.map(key => [key, obj[key]]) ) as Pick<T, K>; } // 调用时指定Person的属性键即可 const johnAsPerson: Person = pick(johnAsDriver, ['id', 'name']);
注意:不要直接使用
const johnAsPerson = johnAsDriver as Person类型断言,这种方式仅在编译期生效,运行时对象仍然会携带driverLicense、carModel等多余属性,序列化或接口传参时容易出现非预期字段。
2 第三方库实现(以Lodash为例)
如果项目中已经引入Lodash,可以直接使用它提供的成熟工具函数,无需自己封装,且自带完善的TS类型支持:
2.1 使用pick指定保留属性
和自己实现的pick逻辑一致,直接指定需要保留的Person属性即可:
import { pick } from 'lodash'; const johnAsPerson: Person = pick(johnAsDriver, ['id', 'name']);
2.2 使用omit指定剔除属性
如果Driver独有属性更少,可以反过来指定要剔除的字段,写法更简洁:
import { omit } from 'lodash'; const johnAsPerson: Person = omit(johnAsDriver, ['driverLicense', 'carModel']);
以上所有方案运行后得到的johnAsPerson都和你手动拷贝属性的运行结果完全一致,且维护成本远低于手动逐个拷贝属性。
内容的提问来源于stack exchange,提问作者Rafael Afonso
相关产品推荐
相关产品推荐

