-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Description
Motivation
It's sometimes very useful to be able to define callbacks that guarantee an error. For example; transforming errors in when.js promises to hide implementation details:
function stuff(): when.Promise<Item> {
return when.reject<Item>(new Error('Oh noes!'));
}
export function tryStuff(): when.Promise<Item> {
return stuff().catch(err => {
log.error('Internal error', err);
throw new InternalError();
});
}
Unfortunately the compiler derives the type of the error handler to be (err: any) => void
and propagates the return type through the definition of catch
resulting in
error TS2012: Cannot convert 'when.Promise<void>' to 'when.Promise<Item>'
Even if the definition of tryStuff
is changed to force the result to the correct type
return stuff().catch<Item>(err => {
log.error('Internal error', err);
throw new InternalError();
});
the same type is derived for the error handler and you instead get
error TS2082: Supplied parameters do not match any signature of call target:
Call signatures of types '(err: any) => void' and '(reason: any) => when.Promise<Item>' are incompatible.
Details
A fully specified example of the same behaviour is
function run<T>(callback: () => T): T {
return callback();
}
run<boolean>(() => {
throw new Error('Failure');
});
which gives the error
error TS2082: Supplied parameters do not match any signature of call target:
Call signatures of types '() => void' and '() => boolean' are incompatible.
Two possible solutions are returning null to trick the compiler into giving the callback a lenient type (I guess it defaults to any
when the only return
returns a null), or explicitly telling the compiler that the callback can return anything.
run<boolean>(() => {
throw new Error('Failure');
return null;
});
run<boolean>(<() => any>(() => {
throw new Error('Failure');
}));
The first runs afoul of unreachable statement lints. The second is just really horrible.
Seeing as the lints are capable of determining that there is no way to return from this callback, it would be nice if the compiler could also check this and give the callback the type () => any
when it can guarantee there is no possibility of returning.