1
let callback1: null | (() => void) = () => {};
let callback2: null | (() => void) = null;
let callback3: null | (() => void) = null;

if (callback1 != null)
    callback1(); // callable

callback2 = () => {}
if (callback2 != null)
    callback2(); // callable

new Promise<void>(() => callback3 = () => {});

if (callback3 != null)
    callback3(); // not callable
    // ^^^
    // This expression is not callable.
    //     Type 'never' has no call signatures.

Playground

It seems like TypeScript is doing some static analysis, but wrongly, as the code works fine in JS:

let callback3 = null;
new Promise(() => callback3 = () => { console.log("It Works"); });
if (callback3 != null)
    callback3();

// output: It Works
Slava Knyazev
  • 5,377
  • 1
  • 22
  • 43
  • "but wrongly," I'd prefer to call it "correctly, since it cannot guarantee this is going to hold true in the general case". Consider if `new Promise(() => callback3 = () => {});` was instead `setTimeout(() => callback3 = () => {});` – VLAZ Jul 21 '22 at 16:55
  • @VLAZ If it can't with 100% certainly rule out the possibility of `() => void`, which I explicitly declared, it has no business discarding it. – Slava Knyazev Jul 21 '22 at 17:40
  • Well, this is a...feature. Although I'd agree it does get in the way some times. It considers the variable *effectively* a constant, since, even though it's a `let`, it's only assigned once. ...if you ignore the callback that also sets it, since TS cannot guarantee it happens synchronously. The effectively a constant thing works in some cases but I still consider it awkward in many others. Some times I just want to prototype some code and use something like `let x: string | number = 42;` and since it's effectively a constant, TS yells at me for treating it as a string. – VLAZ Jul 21 '22 at 17:50

1 Answers1

1

Since you init callback3 with a literal null and you don't modify it, TS infers its type as null.

with if (callback3 != null) you're narrowing it down to never hence the error.

This doesn't happen in this kind of case :

declare const maybeCallback: null | (() => void);

callback3 = maybeCallback;

if(callback3 !== null) {
    // () => void not never
}

Playground

Matthieu Riegler
  • 31,918
  • 20
  • 95
  • 134