"TS2322: Type 'Timeout' is not assignable to type 'number'" when running unit tests

TypescriptUnit TestingKarma RunnerKarma Mocha

Typescript Problem Overview


I have two TypeScript packages, and one package (Package A) depends on the other (Package B). Each package has a unit test set up using Karma. When I run unit tests for each individually after installing all dependencies from NPM, the unit tests run fine. However, if I use npm link package-b in Package A and run Package A's unit tests then, I get the error stated in the title: "TS2322: Type 'Timeout' is not assignable to type 'number'."

The line in question is a call to setTimeout. After digging, I found that while running the tests separately without npm link, TypeScript correctly identifies the setTimeout signature in typescript/lib/lib.dom as the desired type, but in the failing case after using npm link it is using using Node's setTimeout signature in @types/node/index. I confirmed this by changing the return type on setTimeout to string and observing the same error with string in the place of Timeout.

What I am not certain of is why the TypeScript compiler has decided to use the alternative definition in this specific case, nor how I can convince it to use the desired definition. I am happy to post some code, but I am not sure what would be useful in this case given all that is on the failing line is the setTimeout call.

Typescript Solutions


Solution 1 - Typescript

You could try with using window.setTimeout instead of just setTimeout, this way the typescript one will be explicitly used

Solution 2 - Typescript

You can use:

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

It'll pick correct declaration depending on your context.

I'm seeing this discrepency when using vscode/tsc (NodeJS.Timeout) and running ts-jest (number). This is the only way the whole thing typechecks on both sides.

Solution 3 - Typescript

By default, typescript includes all ./node_modules/@types/*. If you have ./node_modules/@types/node there, its timeout typings will override the web typing (that returns a number, and not a NodeJS.Timeout).

You can remedy to that by explicitly emptying your types in your tsconfig.json:

{
  "compilerOptions": {
    "types": []
  }
}

Realistically you're probably in a project where you need other types and libs so you might wanna bring back ES and DOM libs:

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

Solution 4 - Typescript

You can use something like:

let myTimeOut: NodeJS.Timeout | null = null;

myTimeOut = setTimeout(...);

Then when you reset your variable to initial status, you can simply:

myTimeOut = null;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questiondawsonc623View Question on Stackoverflow
Solution 1 - TypescriptPablo MarcanoView Answer on Stackoverflow
Solution 2 - TypescriptMirek RusinView Answer on Stackoverflow
Solution 3 - TypescriptNino FiliuView Answer on Stackoverflow
Solution 4 - TypescriptMarcos MathiasView Answer on Stackoverflow