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

Posted

技术标签:

【中文标题】运行单元测试时,“TS2322:类型 \'Timeout\' 不可分配给类型 \'number\'”【英文标题】:"TS2322: Type 'Timeout' is not assignable to type 'number'" when running unit tests运行单元测试时,“TS2322:类型 'Timeout' 不可分配给类型 'number'” 【发布时间】:2019-08-28 05:24:57 【问题描述】:

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

有问题的线路是对setTimeout 的调用。经过挖掘,我发现在没有npm link 的情况下单独运行测试时,TypeScript 正确地将typescript/lib/lib.dom 中的setTimeout 签名识别为所需的类型,但在使用npm link 后失败的情况下,它使用的是Node 的@987654328 @签名在@types/node/index。我通过将setTimeout 上的返回类型更改为string 并用string 代替Timeout 观察到相同的错误来确认这一点。

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

【问题讨论】:

这能回答你的问题吗? TypeScript - use correct version of setTimeout (node vs window) 【参考方案1】:

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

【讨论】:

这行得通...但是如果我在 React 中的“.tsx”文件中...为什么 TS 不暗示 window 而不必这样做? 如果是 React Native? 看起来 TS 假设我们在 Node 环境中,因为 setTimeout 返回一个 Timeout 对象 谢谢,成功了【参考方案2】:

你可以使用:

let timeoutId: null | ReturnType<typeof setTimeout> = null
...
timeoutId = setTimeout(...)

它会根据你的上下文选择正确的声明。

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

【讨论】:

但是如果您还需要致电clearTimeout 怎么办? (例如,甚至使用setTimeout 的原因是为了去抖动)在我的情况下,出于某种原因,TS 期望setTimeout 返回NodeJS.Timeout,但它仍然期望clearTimeout 收到一个数字... 如果您需要使用clearTimeout(),您可以将变量转换为Number()clearTimeout(Number(timeoutId))【参考方案3】:

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

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


  "compilerOptions": 
    "types": []
  

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


  "compilerOptions": 
    "types": [],
    "lib": ["ESNext", "DOM"]
  

【讨论】:

【参考方案4】:

你可以使用类似的东西:

let myTimeOut: NodeJS.Timeout | null = null;

myTimeOut = setTimeout(...);

然后,当您将变量重置为初始状态时,您可以简单地:

myTimeOut = null;

【讨论】:

以上是关于运行单元测试时,“TS2322:类型 'Timeout' 不可分配给类型 'number'”的主要内容,如果未能解决你的问题,请参考以下文章

Angular:运行Git push时如何强制运行单元测试?

运行单元测试时禁用 Django South?

运行所有测试时单元测试失败,但调试时通过

Visual Studio 单元测试:为啥在测试相同的浮点值时测试运行不确定?

我可以在运行 VS 单元测试时进行调试吗?

使用单元测试时避免运行部分代码