"Function expression, which lacks return-type annotation, implicitly has an 'any' return type" 添加void操作时

"Function expression, which lacks return-type annotation, implicitly has an 'any' return type" when adding void operation

我在 TypeScript 上遇到了一个 st运行ge 问题。我最近了解了 void ... 运算符,因为我需要应用它,这样 eslint 就不会报告 no-floating-promises。然而,这个特定的片段不知何故导致了一个问题,我无法在 TypeScript playground 上重现:

class A {

  async a() {}

  async onTickAsync(repeat: boolean) {
    try {
      await this.a();
    } catch(e) {
      console.error(e);
    } finally {
      if (repeat) {
        window.setTimeout(() => void this.onTickAsync(true), 200);
      }
    }
  }

}

VS Code 会报告这个错误:

TS7011: Function expression, which lacks return-type annotation, implicitly has an 'any' return type.

但是,该问题无法在 TS Playground 上重现。 VS Code 和 Playground 都使用 TypeScript 4.5.4。这是我的 tsconfig.json:

{
    "compileOnSave": true,
    "compilerOptions": {
        "noImplicitAny": true,
        "noEmitOnError": true,
        "sourceMap": true,
        "target": "ESNext",
        "module": "ESNext"
    },
    "exclude": [
        "node_modules"
    ]
}

我知道可以通过添加 : void return 类型或删除 void 操作或删除 noImplicitAny:

来修复它
window.setTimeout((): void => void this.onTickAsync(true), 200);

请问:错误原因是什么?为什么它只发生在我的 IDE/local 而不是操场上?


为了确定这不仅仅是因为 VS Code,我还在单独的终端上 运行 tsc --versiontsc:

tsc --showConfig 输出:

PS C:\Users\lukev\Downloads\Temp> tsc --showConfig
{
    "compilerOptions": {
        "noImplicitAny": true,
        "noEmitOnError": true,
        "sourceMap": true,
        "target": "esnext",
        "module": "esnext"
    },
    "files": [
        "./test.ts"
    ],
    "exclude": [
        "node_modules"
    ],
    "compileOnSave": true
}

同样有趣的是,它不会发生在其他函数上。例如,这不会产生任何错误。好像是window.setTimeout的东西。例如,我发现 Function 类型和 () => void 之间有些不同:

class A {

  doSomething1(_: Function) { }
  doSomething2(_: () => any) { }
  doSomething3(_: () => void) { }

  async a() { }

  async onTickAsync(repeat: boolean) {
    // Only this one produces error
    this.doSomething1(() => void this.onTickAsync(true));
    this.doSomething2(() => void this.onTickAsync(true));
    this.doSomething3(() => void this.onTickAsync(true));
  }

}

我可以重现你的问题,虽然我无法回答为什么会发生这种情况,但你可以通过省略 void operator 和链接来修复编译器错误承诺满足 ESLint 的 catch 方法:

// before
window.setTimeout(() => void this.onTickAsync(true), 200);

// after
window.setTimeout(() => this.onTickAsync(true).catch(() => {}), 200);

请参阅 microsoft/TypeScript#36651 以获得权​​威答案。

您的问题是您启用了 the --noImplicitAny compiler option but you have not enabled the --strictNullChecks compiler option. You can set these options in the TypeScript Playground and reproduce your issue

旁注:请注意 --strictNullChecksthe --strict family of compiler features 的一部分,通常建议将其作为事实上的“标准”类型安全级别的一部分。你并不是真的在问你应该使用哪些编译器选项,但请注意,如果你使用一组不常见的编译器选项,你更有可能 运行 进入一般 TypeScript 社区并不了解的编译器行为.好了,说完了。

所以我们知道如何重现,但还没有明确回答为什么这里有错误。让我们现在就这样做。启用 --strictNullChecks 后,the void opterator produces a value of the undefined type. But with --strictNullChecks disabled, there isn't really a distinct undefined type, and the void operator produces a value of the any type. And unless you explicitly annotate 类型为 any,您将在 --noImplicitAny:

下得到错误
// with --strictNullChecks disabled

() => void 0; // error!
// Function expression, which lacks return-type annotation, 
// implicitly has an 'any' return type.

(): undefined => void 0; // okay
//^^^^^^^^^^^ <-- arrow function return type annotation

如您所见,如果 void 运算符的 return 类型被赋予 contextual type:

,您也可以消除错误
function foo(cb: () => any) { }
foo(() => void 0); // okay, void 0 is contextually typed as any

注意 Function 接口有点奇怪,没有真正的 call signature, see microsoft/TypeScript#20007,所以它不能提供上下文类型:

function bar(cb: Function) { }
bar(() => void 0); // implicit any error!

Playground link to code