打字稿如何从一个类型中解包/删除Promise?

时间:2018-02-23 09:16:02

标签: typescript typescript-typings

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

enter image description here

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

2 个答案:

答案 0 :(得分:7)

你的类型不够准确,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;
}

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

{
    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,但是虽然编译器无法推断它,但它类型安全,因为我们解决了所有的承诺。

答案 1 :(得分:6)

在打字稿2.8之后,我能够使用以下策略

Option Explicit

Sub consolidate()

    Const SHEET_NAME = "Archer Search Report"
    Const NO_OF_COLS = 101

    Dim wb As Workbook, ws As Worksheet
    Dim irow As Long, iLastRow As Long, c As Long, count As Long

    Set wb = ThisWorkbook
    Set ws = wb.Sheets(SHEET_NAME)
    iLastRow = ws.Range("A" & Rows.count).End(xlUp).Row

    ' scan up sheet
    For irow = iLastRow - 1 To 2 Step -1

         ' if same id below
        If ws.Cells(irow + 1, 1) = ws.Cells(irow, 1) Then

            ' scan across
            For c = 1 To NO_OF_COLS
                ' if blank copy from below
                If Len(ws.Cells(irow, c)) = 0 Then
                   ws.Cells(irow, c) = ws.Cells(irow + 1, c)
                End If
            Next

            ws.Rows(irow + 1).Delete
            count = count + 1

        End If

    Next

    MsgBox iLastRow - 1 & " rows scanned" & vbCr & _
           count & " rows deleted from " & ws.Name, vbInformation

End Sub

用法如下

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
}