When it comes to safe callbacks, the ideal scenario is for the function to return either undefined
or nothing at all.
Let's test this with the following scenarios:
declare const fn1: (cb: () => void) => void;
fn1(() => '123'); // no error
Unfortunately, this didn't work out as expected. It seems that string
is not compatible with void
.
Next up:
declare const fn2: (cb: () => unknown) => void;
fn2(() => '123'); // no error
To our surprise, the same issue occurred. Let's try something else.
Testing again:
declare const fn3: (cb: () => undefined) => void;
fn3(() => '123'); // error: Type 'string' is not assignable to type 'undefined'
Progress! An error was thrown this time. Let's proceed with this approach:
fn3(() => undefined); // okay
fn3(() => {}); // error: Type 'void' is not assignable to type 'undefined'
This doesn't meet our requirements.
Considering a different route:
declare const fn4: (cb: () => void | undefined) => void;
fn4(() => undefined); // okay
fn4(() => { }); // okay
fn4(() => '123'); // error: Type 'string' is not assignable to type 'undefined'
Success! This seems like a viable solution.
However, why does void
allow string
, while void | undefined
does not? Is this a bug?
Is it safe to assume this behavior will remain consistent in future TypeScript updates? Are there better alternatives to achieve the same outcome?