如何根据回调的返回类型指定返回类型?

时间:2019-08-06 18:54:01

标签: typescript promise

以下接口定义了一个函数,该函数接受一个回调函数并返回该回调返回的值。

export interface MonitoredOperation {
    <T = any>(operationName: string, operation: () => T | Promise<T>): T | Promise<T>;
}

问题是,如果我在回调将始终返回一种类型的上下文中使用此函数,TypeScript仍然认为外部函数可以返回任一类型。

例如,如果我编写以下代码,

public addNumbersAsync(n1: number, n2: number, n3: number, n4: number): Promise<number> {
    return this.monitoredOperation("addNumbers", () => Promise.resolve(n1 + n2 + n3 + n4));
}

TypeScript抱怨无法将number | Promise<number>分配给Promise<number>

我已经看到一些使用infer来捕获函数的返回值的示例,但是我不确定如何在此处应用它。

如何告诉TypeScript我在这里拥有的信息以及返回类型必须匹配?

编辑:

我需要两种可能的类型,因为我对该接口的实现需要区分它们。如果我的界面仅使用T,则会收到错误Type 'Promise<any>' is not assignable to type 'T'。这是一个简化的版本:

function monitoredOperation<T>(operationName: string, operation: () => T | Promise<T>): T | Promise<T> {
    let onSuccess = (value: T): T => {
        broadcast("finished");
        return value;
    }
    let onFailure = (error: any): never => {
        broadcast("failed");
        throw error;
    }

    try {
        let result = operation();

        if (isPromise(result)) {
            return result.then(onSuccess, onFailure);
        } else {
            return onSuccess(result);
        }
    }
    catch (e) {
        onFailure(e);
    }
}

1 个答案:

答案 0 :(得分:2)

我不确定| Promise<T>会带来什么。没有类型,从类型角度来看,该函数的行为实际上是正确的。 monitoredOperation返回回调返回的内容,无论是Promise还是其他方式:

interface MonitoredOperation {
  <T = any>(operationName: string, operation: () => T): T;
}

class X {
  private monitoredOperation!: MonitoredOperation
  public addNumbersAsync(n1: number, n2: number, n3: number, n4: number): Promise<number> {
    return this.monitoredOperation("addNumbers", () => Promise.resolve(n1 + n2 + n3 + n4));
  }
}

Play

如果您想将Promise保留在签名中(可能是用于文档说明,提示特殊的Promise行为),重载会更好地工作:

interface MonitoredOperation {
  <T = any>(operationName: string, operation: () => Promise<T>): Promise<T>;
  <T = any>(operationName: string, operation: () => T): T;
}

class X {
  private monitoredOperation!: MonitoredOperation
  public addNumbersAsync(n1: number, n2: number, n3: number, n4: number): Promise<number> {
    return this.monitoredOperation("addNumbers", () => Promise.resolve(n1 + n2 + n3 + n4));
  }
}

Play