如何在TypeScript中类型安全地将符合接口A的对象转换为符合接口B的对象?
如何在TypeScript中类型安全地将符合接口A的对象转换为符合接口B的对象?
这确实是TypeScript开发里常见的小痛点,我来给你几个完全类型安全的解决方案,既能满足类型检查要求,又不会留下多余属性或者undefined值~
首先先明确你的接口定义:
interface A { foo: string; bar: number; } interface B { foo: string; }
方案一:手动解构提取目标属性
最简单直接的方式,明确提取你需要的foo属性,生成的对象完全符合B类型,也不会包含多余的bar:
const a = { foo: "baz", bar: 42 }; // 写法1:直接赋值 const b: B = { foo: a.foo }; // 写法2:解构更简洁 const { foo } = a; const b: B = { foo };
这种方法最直观,完全通过TypeScript的类型检查,生成的b对象也确实只有foo属性,完美适配Firestore这类不接受undefined属性的场景。
方案二:封装可复用的类型安全工具函数
如果需要多次进行这类转换,或者目标接口的属性较多,可以写一个通用的pick函数,利用TypeScript的泛型和Pick工具类型来保证类型安全:
// 泛型函数:提取对象中指定的属性,返回对应类型 function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K> { const result = {} as Pick<T, K>; keys.forEach(key => { result[key] = obj[key]; }); return result; } // 使用示例 const a = { foo: "baz", bar: 42 }; const b: B = pick(a, 'foo');
这里的Pick<A, 'foo'>类型和你的B接口完全等价,所以赋值给b时不会有类型问题,而且函数确保我们只能提取原对象存在的属性,避免手动写错属性名。
方案三:通过属性过滤生成新对象
如果目标接口的属性较多,不想一个个手动提取,可以通过过滤对象键值对来生成符合要求的对象:
const a = { foo: "baz", bar: 42 }; // 定义允许的属性列表(和B接口的键对应) const allowedKeys: (keyof B)[] = ['foo']; const b: B = Object.fromEntries( Object.entries(a).filter(([key]) => allowedKeys.includes(key as keyof B)) ) as B;
这里的类型断言as B是安全的,因为我们明确只保留了B接口中定义的属性,生成的对象不会有多余的bar,也不会出现undefined值。
为什么你之前的方法不行?
- 直接
delete b.bar报错:因为TypeScript认为b是B类型,不存在bar属性,所以编译器会阻止这个操作; - 赋值
bar: undefined:虽然类型上符合,但实际对象中会保留bar: undefined这个键值对,这会导致像Firestore这类工具拒绝接收,不符合你的需求; - 使用
any:确实能绕开类型检查,但完全失去了TypeScript的类型安全保障,不推荐。
备注:内容来源于stack exchange,提问作者Jonas Sourlier
相关产品推荐
相关产品推荐

