【问题标题】:typescript how to unwrap/remove Promise from a type?typescript 如何从类型中解包/删除 Promise?
【发布时间】:2018-08-03 07:33:43
【问题描述】:

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

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
  })
}

【问题讨论】:

  • 你需要安装typescript@next或者等待TypeScript 2.8发布。它将带来允许unwrap a promise type的条件类型。

标签: typescript typescript-typings


【解决方案1】:

打字稿 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>>;

【讨论】:

  • 关于时间TS!!!谢谢!
【解决方案2】:

在 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)),
})

【讨论】:

    【解决方案3】:

    您的类型不够准确,TypeScript 编译器无法确定它们不是 Promise。

    你需要的是这样的:

    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 版本中使用各种 Promise 类型,但正如 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 的方法,但尽管编译器无法推断它,但它是类型安全的,因为我们解决了所有承诺。

    【讨论】:

    • 2.8 版本有效!感谢您为我编写它,因为它非常复杂.. 我想不通
    • @StephenBugsKamenar 我又在玩这个例子,我认为我的第一个答案不太正确。特别是,我认为promise_props&lt;T&gt;(obj: {[k in keyof T]: Promise&lt;T[k]&gt;}) 的定义并不好,因为如果我们认为T[k] 也是一个promise,它就是在promise 中包装了一个promise。现在我已经更新了它。它更简单,使用与 2.7 版本相同的实现。等 2.8 正式出,我再试一次。
    • 我被困在没有内置 Awaited 类型的 typescript v4.2.4 中。我用你的 UnPromisify 重命名为 Awaited 并且工作得很好。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-08
    • 2021-10-17
    • 2014-07-14
    • 2019-01-27
    • 2019-12-05
    相关资源
    最近更新 更多