typescript如何从类型中展开/删除Promise?

y53ybaqx  于 2022-12-24  发布在  TypeScript
关注(0)|答案(3)|浏览(189)

我有一个函数,它接受一个对象,其中每个属性都是一个承诺。它等待所有的承诺完成,然后返回一个新的对象,该对象具有相同的属性,但现在已解析了值。

resolved_props.company应该是string,而不是Promise<string>

// TODO: fix the types on this
function promise_props<T>(obj:T):Promise<T> {
  const keys = Object.keys(obj)
  const len = keys.length
  const awaitables = new Array<T>(len)
  for (var i = 0; i < len; i++) awaitables[i] = (obj as any)[keys[i]]

  return Promise.all(awaitables).then((results) => {
    const byName:any = {}
    for (var i = 0; i < len; i++) byName[keys[i]] = results[i]
    return byName
  })
}
zaqlnxep

zaqlnxep1#

typescript 4.5

实用程序类型Awaited正式内置于typescript v4.5中。
https://devblogs.microsoft.com/typescript/announcing-typescript-4-5/#awaited-type

// A = string
type A = Awaited<Promise<string>>;

// B = number
type B = Awaited<Promise<Promise<number>>>;

// C = boolean | number
type C = Awaited<boolean | Promise<number>>;
bf1o4zei

bf1o4zei2#

您的类型不够准确,TypeScript编译器无法判断它们此时是否是承诺的类型。
你需要的是这样的东西:

async function promise_props<T>(obj: {[key: string]: Promise<T>}): Promise<{[key: string]: T}> {
    const keys = Object.keys(obj);
    const awaitables = keys.map(key => obj[key]);

    const values = await Promise.all(awaitables);
    const result: {[key: string]: T} = {};

    keys.forEach((key, i) => {
        result[key] = values[i];
    });
    return result;
}

但只有当你的对象有相同类型的承诺时,它才会起作用,例如:

{
    company: Promise.resolve("company"),
    page: Promise.resolve("1")
};

我不确定在当前的TypeScript版本中是否有可能让它与各种承诺类型一起工作,但正如Tao所建议的,您可以使用TypeScript 2.8中的新特性来让它工作:

type UnPromisifiedObject<T> = {[k in keyof T]: UnPromisify<T[k]>}
type UnPromisify<T> = T extends Promise<infer U> ? U : T;

async function promise_props<T extends {[key: string]: Promise<any>}>(obj: T): Promise<UnPromisifiedObject<T>> {
    const keys = Object.keys(obj);
    const awaitables = keys.map(key => obj[key]);

    const values = await Promise.all(awaitables);
    const result = {} as any;

    keys.forEach((key, i) => {
        result[key] = values[i];
    });
    return result as UnPromisifiedObject<T>;
}

async function main() {
    const x = {
        company: Promise.resolve("company"),
        page: Promise.resolve(1)
    };
    const res = await promise_props(x);
    const company = res.company;  // company is a string here
    const page = res.page;        // page is a number here
}

正如你所看到的,返回类型被正确地推断出来了。我认为方法的实现可以改进。我找不到一种方法来示例化返回类型的示例并使用any,但是尽管编译器不能推断它,它是类型安全的,因为我们解决了所有的承诺。

bfhwhh0e

bfhwhh0e3#

在typescript 2.8之后,我能够使用以下策略

export type Await<T> = T extends Promise<infer U> ? U : T
export type AwaitProps<T> = {[P in keyof T]: Await<T[P]>}

export async function concurrent<T>(obj: T): Promise<AwaitProps<T>> {
    const keys = Object.keys(obj)
    const awaitables = keys.map(key => obj[key])
    const values = await Promise.all(awaitables)
    const result = {}
    keys.forEach((key, i) => result[key] = values[i])
    return <AwaitProps<T>>result
}

用法如下

const {claimRow, profileRow} = await concurrent({
    claimRow: claimTable.one(identify(userId)),
    profileRow: profileTable.one(identify(userId)),
})

相关问题