Typescript 使用短主体箭头函数推断 void 返回类型,但不是常规箭头函数

dbz*_*299 6 typescript typescript-generics

在打字稿文档中,它指出

\n
\n

void表示不返回值的函数的返回值。每当函数没有任何 return 语句,或者不从这些 return 语句返回任何显式值时,它就是推断类型。

\n
\n

很清楚它的void作用,但我不明白为什么打字稿编译器似乎没有推断出第一个代码块的返回类型为 ,void因为没有返回值或返回语句。

\n

为什么第一次forEach通话有效?forEach由于没有返回值,第一次调用不应该与第二次调用有相同的错误吗?

\n
function forEach<T>(arr: T[], callbackFn: (arg: T, idx: number) => undefined): void {\n  for (let i = 0; i < arr.length; i++) {\n    callbackFn(arr[i], i)\n  }\n}\n\n// works\nforEach([1, 2, 3], (arg, idx) => {\n  console.log({arg, idx})\n})\n\n// error Type \'void\' is not assignable to type \'undefined\'\n// here void is inferred\nforEach([1, 2, 3], (arg, idx) => console.log({arg, idx}))\n
Run Code Online (Sandbox Code Playgroud)\n

jca*_*alz 6

在 5.1 之前的每个 TypeScript 版本中,您的第一次调用也会出错:

\n
function foo(cb: () => undefined) { }\nfoo(() => { console.log() }); // ERROR in TS5.0 and below:\n//  ~~~~~~~~~~~~~~~~~~~~~~~\n// Argument of type \'() => void\' is not assignable to parameter of type \'() => undefined\'.\n// Type \'void\' is not assignable to type \'undefined\'.\n
Run Code Online (Sandbox Code Playgroud)\n

但 TypeScript 5.1 引入了对返回函数更简单的隐式返回的undefined支持。特别是,“如果一个函数没有返回表达式,并且被传递给需要返回 的函数undefined,则 TypeScript 会推断undefined该函数\xe2\x80\x99s 返回类型。” 这就是它起作用的原因,至少如果您处于期望的上下文undefined中:

\n
foo(() => { console.log() }); // okay in TS5.1+\n// no return statement in the function body, \n// inferred as undefined to satisfy context\n
Run Code Online (Sandbox Code Playgroud)\n

这就是所问问题的答案。

\n
\n

请注意,如果您不在这样的上下文中,相同的主体仍然会被推断为返回void,而不是undefined返回,这意味着您的第一次调用看似等效的两步版本将会失败,即使在 TS5.1 中也是如此:

\n
const cb = () => { console.log() };\n// const cb: () => void\n\nfoo(cb); // error!\n//  ~~\n// Argument of type \'() => void\' is not assignable to parameter of type \'() => undefined\'.\n// Type \'void\' is not assignable to type \'undefined\'.\n
Run Code Online (Sandbox Code Playgroud)\n
\n

另请注意,第二个代码块在所有版本中都会失败。具有简洁主体的箭头函数就像() => expr隐式return主体表达式一样,而具有块主体的箭头函数则仅在主体中() => { expr }有语句时才返回一个值。return

\n

因此, while() => { console.log() }不返回任何内容,() => console.log()而是返回console.log()计算结果。根据TS 库的 console.log()returns void,意思是“这个函数可能会返回任何东西,所以不要对返回值做任何事情”。(是的,void很奇怪,请参阅为什么未定义可分配给 void?

\n

也许应该undefined,因为我们知道这就是它在运行时实际返回的内容,但它是void,所以这就是编译器所知道的。如果console.log()可能评估任何东西,它会在undefined需要的地方被拒绝:

\n
foo(() => console.log())\n// -----> ~~~~~~~~~~~~~\n// Type \'void\' is not assignable to type \'undefined\'.\n
Run Code Online (Sandbox Code Playgroud)\n

Playground 代码链接

\n