【问题标题】:Typescript: Error on function argument when the function can be of multiple function types打字稿:当函数可以是多种函数类型时,函数参数出错
【发布时间】:2021-11-14 05:32:15
【问题描述】:

我有以下示例代码:

type GetMultipleFunction1 = () => Promise<string[]>; 
type GetMultipleFunction2 = (data: number) => Promise<string[]>; 
type GetMultipleFunction = GetMultipleFunction1 | GetMultipleFunction2;

function test(func: GetMultipleFunction): Promise<string[]> {
    return func(); 
}

function getStrings(data: number): Promise<string[]> {
    return new Promise(function (resolve, reject) {
        resolve(['hello', 'hi']);
    }) }

test(getStrings);

为什么会出现错误(return func() 的第 6 行):

预期 1 个参数,但得到 0 个。

我觉得 GetMultipleFunction 可以是类型 1 或类型 2。类型 1 不需要参数。

如何更改我的代码以消除警告?

Typescript Playground

--

编辑:我想要实现的目标:

我基本上想要一个接受函数作为参数的函数。在我的例子中test。它应该接受一个带参数的函数和一个不带参数的函数。这可能吗?

代码示例:

type GetMultipleFunction1 = () => string[];
type GetMultipleFunction2 = (data: number) => string[];
export type GetMultipleFunction = GetMultipleFunction1 | GetMultipleFunction2;

function test(func: GetMultipleFunction, data?: number): string[] {
    if (data) return func(data);
    return func()  // here should be no warning
}

function getStrings1(data: number): string[] {
    return [`hello-${data}`, 'hi'];
}

function getStrings2(): string[] {
    return ['hello', 'hi']
}

test(getStrings1, 2);
test(getStrings2);

Typescript Playground

--

我想要实现的更具体的解释:我正在使用 Vue3 组合函数来提取 Get 请求。通常我可以直接调用:/api/groups/,但有时我需要将参数传递给我的 get 请求函数:/api/groups/3/members/ 现在需要将数字 3 作为参数传递。

【问题讨论】:

  • 为什么要使用多种类型?只需dataoptional
  • 嗯,我想过,但后来我得到另一个错误:键入'number | undefined' 不可分配给类型 'number'。在 test(getStrings) 的最后一行。见:typescriptlang.org/play?#code/…
  • 一般来说,只要没有出现其他错误,我就可以接受可选的数据。
  • test 的目的是什么?现在在我看来,这个错误是完全有效的:你正在调用func,但没有传入func 需要的数据。因此,修复它的两种可能方法是:1)传入它需要的数据,或者 2)重写一些东西,使它不需要数据。但我不知道如何建议你,因为我不明白代码的目的。
  • 使datagetStrings 以及typescriptlang.org/play?#code/… 中成为可选的

标签: typescript


【解决方案1】:

问题出在这一行type GetMultipleFunction = GetMultipleFunction1 | GetMultipleFunction2;

两个函数的联合永远不会以您期望的方式运行。 它产生一个函数,其中参数是两个函数参数的相交类型。 看小例子:

type Foo = (arg: { age: number }) => void
type Bar = (arg: { name: string }) => void

type Union = Foo | Bar

declare let func:Union

// let func: (arg: { age: number;} & { name: string;}) => void
func()

这是设计使然,这是调用函数联合的最安全方式。

在你的例子中:

function test(func: GetMultipleFunction): Promise<string[]> {
    return func(); // < ------ ERROR
}

调用func 的最安全方法是提供参数。它将涵盖两种情况。如果你传递了一个不需要参数的函数 - 它不会造成任何伤害。

我认为在这个例子中使用函数交集而不是联合是值得的。喜欢这里:

type GetMultipleFunction1 = () => Promise<string[]>;
type GetMultipleFunction2 = (data: number) => Promise<string[]>;
export type GetMultipleFunction = GetMultipleFunction1 & GetMultipleFunction2;

function test(func: GetMultipleFunction): Promise<string[]> {
    return func(); // no error
}

function getStrings(data: number): Promise<string[]> {
    return new Promise(function (resolve, reject) {
        resolve(['hello', 'hi']);
    })
}

test(getStrings); // error

但是,我们在一个新地方遇到了错误:test(getStrings); // error

这是因为Type '(data: number) =&gt; Promise&lt;string[]&gt;' is not assignable to type '() =&gt; Promise&lt;string[]&gt;'.

我很难猜出你想在这里实现什么。 getStrings 中的 data 参数未使用。

你也可以重载你的test函数:

type GetMultipleFunction1 = () => Promise<string[]>;
type GetMultipleFunction2 = (data: number) => Promise<string[]>;

function test(func: GetMultipleFunction2): Promise<string[]>
function test(func: GetMultipleFunction1): Promise<string[]>
function test(func: (...args: any[]) => Promise<string[]>): Promise<string[]> {
    return func(); // ok
}

function getStrings(data: number): Promise<string[]> {
    return new Promise(function (resolve, reject) {
        resolve(['hello', 'hi']);
    })
}

test(getStrings); // ok

test(() => Promise.resolve(42)); // expected error

别担心我用过(...args: any[]),测试功能仍然只接受 GetMultipleFunction1GetMultipleFunction2

更新

您可以完全摆脱联合函数和重载。只需使用其余参数


function test<Fn extends (...args: any[]) => string[]>(func: Fn, ...params: Parameters<Fn>): string[] {
    return func(...params)  // ok
}

function getStrings1<Data extends number>(data: Data) {
    return [`hello-${data}`, 'hi'];
}

function getStrings2() {
    return ['hello', 'hi']
}

test(getStrings1, 2);
test(getStrings1); // expected error
test(getStrings2);

Playground

【讨论】:

  • 非常感谢您的回答。我已经添加了对我想要实现的目标的更好解释。我的第二个代码示例与我的原始代码基本相同。测试 func 决定如何调用 func()。也许我应该只做 test1() 或 test2()。但我想知道是否有可能通过单个功能实现我想要实现的目标。
  • @danielmoessner 进行了更新
  • 我不知道真正有趣的参数。它有效。谢谢
猜你喜欢
  • 2020-10-23
  • 2021-09-06
  • 2019-03-20
  • 2020-05-09
  • 2022-01-12
  • 1970-01-01
  • 2022-11-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多