Strange TypeScript typing issue (TS error code 2349)

Issue

Why do I get a compile error with the following code snippet?

let f: (() => void) | null = null

function g() {
  f = () => {}
}

g()

if (f) {
  f() // <- Error: "This expression is not callable 
      //            Type 'never' has no call signatures. (2349)"
}

TypeScript Playground demo

Solution

Because TypeScript doesn’t know that g assigns to f, its flow analysis for the purposes of narrowing types doesn’t go that deep. As a result, when it reaches if (f) it thinks f is null (because it’s narrowed the type based on the assignment that it did see, so it thinks that f has the type null at that point), so within the if the type of f has been narrowed further to never (because TypeScript thinks you’ll never go into that if), which isn’t callable. You can see this if you hover your mouse over f in the if condition (it says the type is null) and then hover over it in the body of the if (it says the type is never).

If you tweak your example so that TypeScript’s flow analysis can see that f may not be null anymore, the error goes away:

let f: (() => void) | null = null

if (Math.random() < 0.5) {
  f = () => {}
}

if (f) {
  f() // <- Error: "This expression is not callable 
      //            Type 'never' has no call signatures. (2349)"
}

Playground Link

I suspect (but don’t know) that this is just one of several pragmatic limits on the analysis that the TypeScript compiler has to ensure that performance is acceptable. jcalz provides this illuminating link discussing the trade-offs and issues. The take-away message is: Control-flow analysis doesn’t cross function boundaries.

Answered By – T.J. Crowder

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published