【问题标题】:How to infer return type of Promise based on function arguments?如何根据函数参数推断 Promise 的返回类型?
【发布时间】:2020-06-06 04:06:46
【问题描述】:
type Actions =
  | ['add', number, number] // should return number
  | ['log', string]; // should return void


type Call = (...args: Actions) => Promise<?>;

const call: Call = (...args: Actions): Promise<?> => {
  // returns some Promise
}

call('add', 1, 1).then(value => {
   // value is then inferred as number
})


call('log', 'Hello World!').then(value => {
   // value is then inferred as void
})

您如何根据传递给函数的任何参数来确定 Promise 的返回值?

【问题讨论】:

  • 上面Call类型的作用是什么?
  • 为什么是call('add', 1, 1) 而不仅仅是add(1,1)call-function 的目的是什么?
  • @T.J.Crowder 对我来说似乎是一种多重调度形式。在这种情况下,Actions 表示要调用的内容和要调用的参数。不过,似乎应该有一种更好的方法来为此生成类型,而不仅仅是元组。
  • @Thomas call 有很多实现细节,无论它采用哪些参数。将其视为fetch,但基于提供的 URL 的承诺返回类型。
  • @T.J.Crowder 在这个例子中,它并没有真正做太多。它只是从真正的代码库中遗留下来的,可以删除。

标签: javascript typescript promise


【解决方案1】:

两种方法适合您:

  1. Call 类型作为重载函数类型
  2. 只有一个重载函数。

用你的Call 输入

您想要的Call 类型是重载函数类型。你可以这样定义:

type Call = {
    (...args: ['add', number, number]): Promise<number>;
    (...args: ['log', string]): Promise<void>;
};

由于您需要将返回类型与参数列表相关联,Actions 类型并没有真正的帮助。

使用该类型键入的函数将执行您要求的推理:

function doSomething(fn: Call) {
    fn('add', 1, 2)
        .then(value => {
            // Here, TypeScript infers `value` is of type `number`
        });
    fn('log', 'message')
        .then(value => {
            // Here, TypeScript infers `avlue` is of type `void`
        });
}

On the playground

如果您要为此编写函数,使用一些辅助类型可能会有所帮助:

type AddParams = ['add', number, number];
type LogParams = ['log', string];
type ActionParams =
    | AddParams
    | LogParams;

type Call = {
    (...args: AddParams): Promise<number>;
    (...args: LogParams): Promise<void>;
};

那么例如:

const call: Call = (...args: ActionParams): Promise<any> => {
    // (Dummy implementation)
    if (args[0] === 'add') {
        return Promise.resolve(args[1] + args[2]);
    }
    return Promise.resolve();
};

On the playground

只有一个重载函数

如果你只是想写一个重载函数,你不需要Call类型(你可能知道):

type AddAction = ['add', number, number];
type LogAction = ['log', string];
type Actions =
    | AddAction
    | LogAction;

function call(...args: AddAction): Promise<number>;
function call(...args: LogAction): Promise<void>;
function call(...args: Actions): Promise<any> {
    // ...implementation...
}

call('add', 1, 2)
    .then(value => {
        // Here, TypeScript infers `value` is of type `number`
    });
call('log', 'message')
    .then(value => {
        // Here, TypeScript infers `avlue` is of type `void`
    });

On the playground

【讨论】:

  • 如果不重载函数声明,我当然想不出更好的方法。我不确定 TS 是否支持足够的逻辑来说出诸如“此函数将元组作为输入并返回元组中定义的最后一个类型”之类的内容或任何类似的内容。即使是这样,我仍然觉得重载更清晰,因为它更明确。
猜你喜欢
  • 1970-01-01
  • 2021-07-18
  • 2020-02-28
  • 1970-01-01
  • 1970-01-01
  • 2021-12-09
  • 2020-12-26
  • 1970-01-01
相关资源
最近更新 更多