Tobías
Tobías

Reputation: 6297

Typescript type definition vs inference

In the below example:

Playground Link

type Foo = () => void;
let a: Foo | undefined = undefined;

const c = () => { a = () => console.log("Hi!") };
c();

if (a) {
  a();
}

At line 4 the type of a is let a: Foo | undefined but at line 8 it is let a: never. Therefore tsc shows this error: Type 'never' has no call signatures at line 8.

But it doesn't if line 2 is let a: Foo | undefined; (removed the variable assignment)

I guess it will be something related with Type Inference. The docs states that:

In TypeScript, there are several places where type inference is used to provide type information when there is no explicit type annotation.

let x = 3;
    ^
    let x: number

But I this example there is an explicit type annotation.

I understand that TS cannot know if the function c will be executed and, therefore, that a will be assigned. That is why I have put the explicit definition of the type of a in its declaration.

So why is the type defined for a not respected at line 8?

Upvotes: 3

Views: 131

Answers (1)

kaya3
kaya3

Reputation: 51132

This is unsound behaviour, as you note in your question. The behaviour is noted in an open issue on the GitHub issue tracker, titled Trade-offs in Control Flow Analysis:

Optimistic: Bad behavior on locals

The TypeScript compiler has code like this:

enum Token { Alpha, Beta, Gamma }
let token = Token.Alpha;
function nextToken() {
    token = Token.Beta;
}
function maybeNextToken() {
    if (... something ...) {
        nextToken();
    }
}

function doSomething() {
    if (token !== Token.Alpha) {
        maybeNextToken();
    }
    // is this possible?
    if (token === Token.Alpha) {
        // something happens
    }
}

Optimistically assuming token isn't modified by maybeNextToken incorrectly flags token === Token.Alpha as an impossibility. However, in other cases, this is a good check to do! See later examples.

The problem is that making the compiler more pessimistic would be detrimental in other cases, because the compiler would fail to detect real bugs in your code. As of writing this answer, the issue is over 5 years old and still open, and it looks like the language designers haven't agreed on whether anything needs to be done about it, or if so what.

Upvotes: 1

Related Questions