“TS2322:运行单元测试时,类型 'Timeout' 不可分配给类型 'number'”

daw*_*623 46 unit-testing typescript karma-runner karma-mocha

我有两个 TypeScript 包,一个包(包 A)依赖于另一个(包 B)。每个包都有一个使用 Karma 设置的单元测试。从 NPM 安装所有依赖项后,当我为每个单独运行单元测试时,单元测试运行良好。但是,如果我npm link package-b在包 A 中使用并运行包 A 的单元测试,我会收到标题中所述的错误:“TS2322:类型‘超时’不可分配给‘数字’类型。”

有问题的线路是对 的调用setTimeout。挖后,我发现,虽然单独运行测试,没有npm link,打字稿正确识别setTimeout的签名typescript/lib/lib.dom为所需的类型,但在使用后出现故障的情况下,npm link它使用节点的使用setTimeout中的签名@types/node/index。我通过将返回类型更改setTimeoutstringstringTimeout.

我不确定的是为什么TypeScript 编译器决定在这种特定情况下使用替代定义,也不确定我如何说服它使用所需的定义。我很高兴发布一些代码,但我不确定在这种情况下什么有用,因为失败的线路上只有setTimeout调用。

小智 91

您可以尝试使用 usingwindow.setTimeout而不是 setTimeout,这样将显式使用打字稿

  • 如果是 React Native 呢? (7认同)
  • 这有效...但是如果我在 React 中的“.tsx”文件中...为什么 TS 不需要这样做就暗示“window”? (3认同)

Mir*_*sin 51

您可以使用:

let timeoutId: null | ReturnType<typeof setTimeout> = null
...
timeoutId = setTimeout(...)
Run Code Online (Sandbox Code Playgroud)

它将根据您的上下文选择正确的声明。

我在使用 vscode/tsc (NodeJS.Timeout) 和运行 ts-jest (number) 时看到了这种差异。这是整个事情在双方进行类型检查的唯一方式。

  • 太完美了,非常感谢@mirek-rusin (4认同)
  • 如果您需要使用“clearTimeout()”,您可以将变量转换为“Number()”:“clearTimeout(Number(timeoutId))” (4认同)

Nin*_*liu 45

默认情况下,typescript包含所有./node_modules/@types/*. 如果你在./node_modules/@types/node那里,它的超时输入将覆盖网络输入(返回一个数字,而不是一个NodeJS.Timeout)。

您可以通过显式清空您的类型来解决这个问题tsconfig.json

{
  "compilerOptions": {
    "types": []
  }
}
Run Code Online (Sandbox Code Playgroud)

实际上,您可能在一个需要其他类型和库的项目中,因此您可能想带回 ES 和 DOM 库:

{
  "compilerOptions": {
    "types": [],
    "lib": ["ESNext", "DOM"]
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 令我困扰的是,这不是公认的答案。这个被接受的答案感觉非常像 StackOverflow 的刻板印象:“问:我如何使用 X?答:你不,使用 Y 代替,使用 X 是愚蠢的。” (15认同)

Ole*_*ndr 8

添加到Mirek Rusin 的答案。

对于调用,clearTimeout您应该使用 typeundefined而不是null

 let timeoutId: undefined | ReturnType<typeof setTimeout>;

 timeoutId = setTimeout(() => {
   // ...
 }, 1000);

 clearTimeout(timeoutId);
Run Code Online (Sandbox Code Playgroud)