Typescript 异步函数返回类型 void 与 Promise<void>

zim*_*mex 12 typescript

typescript void 和 Promise<void> 类型之间有区别吗?

问是因为我很困惑为什么这是一个有效的打字稿?

const asyncFunc: () => void = async () => {
    await new Promise(resolve => resolve());
};
Run Code Online (Sandbox Code Playgroud)

这不应该是唯一有效的情况吗?

const asyncFunc: () => Promise<void> = async () => {
    await new Promise(resolve => resolve());
};
Run Code Online (Sandbox Code Playgroud)

Ale*_* L. 14

是的,有区别

void 有点像 any 的对立面:根本没有任何类型。您可能通常将此视为不返回值的函数的返回类型

我想Promise<void>不需要解释。


现在为什么允许问题中的分配?因为目标函数 ( () => void) 可以在所有(*几乎)与源函数相同的情况下被调用。看看简化的例子:

declare let voidFunc: () => void;
declare let promiseFunc: () => Promise<void>;

voidFunc = promiseFunc; // OK
promiseFunc = voidFunc; // Error: Type 'void' is not assignable to type 'Promise<void>'
Run Code Online (Sandbox Code Playgroud)

  • @GernotRaudner 是的,这可能是一个大问题。根据我的经验,这是一个更常见的错误。那些不熟悉该行为的人可能会认为这将是顺序的,但它是并行的,没有错误处理:`largeArray.forEach(async (num: number) =&gt; wait realExppressiveCall(num));`。与 `stream.on('event', async () =&gt;` 相同。请参阅此 eslint 插件:https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs /规则/no-misused-promises.md (3认同)
  • 伟大的!你用比我少得多的词解释了同样的事情:-)喜欢这个解释! (2认同)
  • 恕我直言,这是一个陷阱,在严格模式下执行此操作的打字稿并不是我所期望的,因为它很乐意让您留下未处理的承诺拒绝。想象一下这样的事情:https://www.typescriptlang.org/play?ssl=9&amp;ssc=4&amp;pln=1&amp;pc=1#code/MYewdgzgLgBAZmAMgS2gLhgCkwShgXgD4YA3EZAExwG0BdAmOgbgFgAoduAVzGCmXAwoAJ2QBzMQFNhAMUi4YAb3YxV8JKigA6OCGE BRAIbAAFpgQFiCXDlZsAvu04boWgA5cIZwxACeveB4+ATAFZTY1IRNhEAB3GDBJeP1hGOFMACIwEFhQEAAbDNt2e1sgA 而不是取消代码执行,这将默默失败(可能会出现未处理的承诺拒绝警告)。 (2认同)

Tha*_*guy 9

这也可以工作(请注意,这甚至不是一个异步函数):

const asyncFunc: () => void = () => {
  return Math.random() > 0.5 ? 'hello' : 'world';
};

// OR this:
const asyncFunc2: () => void = () => {
  return { nice: 'very '};
};
Run Code Online (Sandbox Code Playgroud)

为什么??基本上,您可以让打字稿解释类型本身,或者您可以将特定类型设置为常量。

在这里,您定义了一个名为 的常量asyncFunc,其类型为() => void。这意味着打字稿在定义类型时将忽略函数的返回值。可以认为用户不需要一个值,因此返回一个值应该仍然可以正常工作并且不会破坏代码。

那么,什么类型的asyncFunc

如果您自己定义常量的类型,则类型将为() => void,因此用户不会期望任何返回值: 在此输入图像描述

但如果你让打字稿自己解释它,它应该知道正确的值。因此,对于上面定义的函数(没有异步),它将是() => string

在此输入图像描述

那你该怎么办?

特别是对于将函数定义为 的情况() => void,该函数根本不会检查返回值,并且您可以返回任何内容(甚至是承诺)。 将函数定义为 async 只会将返回值包装在 Promise 中,该() => void类型将忽略它。

如果要定义与解释类型不同的返回值类型,可以定义一个异步函数来返回具有嵌套类型的特定 Promise。

对于你的例子来说是这样的:

const asyncFunc: () => Promise<void> = async () => {
    await new Promise(resolve => resolve());
};
Run Code Online (Sandbox Code Playgroud)

问题是,这将在没有类型定义的情况下自动发生: 在此输入图像描述

所以这是相当多余的。你可以让打字稿解释类型,除非你想将返回类型更改为其他类型。

因此,在可能返回的示例中,hello或者world我们可能想让用户知道返回值可以是任何字符串而不是这两个值。然后,将返回值的定义更改为其他内容是有意义的: 在此输入图像描述

您可以组合其中任何一个来实现您喜欢的工作流程,但请注意,这() => void是此类型系统的一种特殊情况(因为除此之外的任何其他返回值void都会引发类型错误。


Ped*_*ter 8

当你用类型声明一个变量时() => void,你基本上是在说它可以是任何函数。所以它的值(函数)可以返回任何东西。看看这个游乐场。我向您提供了更多函数实现,以了解声明接收函数的变量与声明函数本身不同。声明函数本身具有您期望的行为。

const asyncFunc: () => void = async () => {
    await new Promise(resolve => resolve());
};

const asyncFunc2: () => Promise<void> = async () => {
    await new Promise(resolve => resolve());
};

const asyncFunc3 = async () => {
    await new Promise(resolve => resolve());
};

// TS compiler complains about it
async function asyncFunc4(): void {
    await new Promise(resolve => resolve());
}

async function asyncFunc4(): Promise<void> {
    await new Promise(resolve => resolve());
}
Run Code Online (Sandbox Code Playgroud)

编辑: 找到这个小解释。它也可以帮助你理解它。它说:

对于其值将被忽略的回调,请使用返回类型 void。原因:使用 void 更安全,因为它可以防止您意外地以未经检查的方式使用 x 的返回值