TypeScript中如何将「属性为Promise的对象」类型转换为「属性为Promise解析后值的对象」类型?
实现Promise对象的类型安全解析
当然可以做到!这其实是TypeScript泛型和工具类型的经典应用场景,正好能满足你保持类型安全的需求。
第一步:定义类型转换工具
我们需要一个泛型类型,把输入对象中每个Promise类型的属性,转换成其解析后的结果类型。TypeScript 4.5+提供的Awaited工具类型可以完美帮我们提取Promise的解析值,结合映射类型就能实现这个转换:
type ResolvedPromiseObject<T> = { [K in keyof T]: Awaited<T[K]>; };
这个类型的作用很直观:
- 遍历输入类型
T的所有键K - 对每个键对应的属性值
T[K],用Awaited提取出Promise最终resolve的类型 - 最终生成一个和原对象结构完全一致,但属性值都是解析后类型的新类型
第二步:完善函数的返回类型与实现
接下来我们把这个类型应用到你的函数中,同时添加必要的类型约束和安全断言,让TypeScript能正确推断类型:
type ResolvedPromiseObject<T> = { [K in keyof T]: Awaited<T[K]>; }; export async function resolveAllObject<T extends Record<string, Promise<any>>>( promiseObject: T ): Promise<ResolvedPromiseObject<T>> { // 初始断言为目标类型,因为我们后续会逐个赋值所有属性 const resolvedPromiseObject = {} as ResolvedPromiseObject<T>; for (const key in promiseObject) { // 确保只处理对象自身的属性(避免遍历原型链) if (Object.prototype.hasOwnProperty.call(promiseObject, key)) { resolvedPromiseObject[key] = await promiseObject[key]; } } return resolvedPromiseObject; }
关键细节说明:
- 泛型约束:
T extends Record<string, Promise<any>>确保传入的参数必须是一个所有属性都是Promise的对象,避免传入不符合要求的参数导致类型错误。 - 类型断言:
{} as ResolvedPromiseObject<T>是必要的,因为初始空对象的类型是{},TypeScript无法自动推断它会被填充成目标类型,而我们明确知道后续会赋值所有属性,所以这个断言是安全的。 Awaited的优势:相比手动写条件类型T extends Promise<infer U> ? U : T,Awaited还能处理嵌套Promise(比如Promise<Promise<number>>)的情况,鲁棒性更强。
使用示例
我们用你提供的IPromiseObject来测试这个函数:
interface IPromiseObject { promiseA: Promise<number>; promiseB: Promise<string>; } async function testResolveAll() { const promiseObj: IPromiseObject = { promiseA: Promise.resolve(42), promiseB: Promise.resolve("TypeScript") }; const resolvedObj = await resolveAllObject(promiseObj); // resolvedObj的类型自动推断为:{ promiseA: number; promiseB: string } // 这里的操作完全是类型安全的,TypeScript会提供正确的代码提示 console.log(resolvedObj.promiseA.toFixed(1)); // 42.0 console.log(resolvedObj.promiseB.toUpperCase()); // TYPESCRIPT }
这样就能完美实现你想要的效果:解析Promise对象时全程保持类型安全,函数返回的类型和你期望的IResolvedPromiseObject完全一致。
内容的提问来源于stack exchange,提问作者Neidi
相关产品推荐
相关产品推荐

