Some libraries offer Thenable
Interface typings f.e. AJV.
There is something I don't understand about them. Given this minimal code
const foo: Ajv.Thenable<boolean> = new Promise<boolean>((resolve, reject) => {
if ("condition")
resolve(true)
reject("Nope")
})
the TypeScript compiler throws an error which I can't wrap my head around.
error TS2322: Type 'Promise<boolean>' is not assignable to type 'Thenable<boolean>'.
Types of property 'then' are incompatible.
Type '<TResult1 = boolean, TResult2 = never>(onfulfilled?: ((value: boolean) => TResult1 | PromiseLike<...' is not assignable to type '<U>(onFulfilled?: ((value: boolean) => U | Thenable<U>) | undefined, onRejected?: ((error: any) =...'.
Types of parameters 'onfulfilled' and 'onFulfilled' are incompatible.
Type '((value: boolean) => U | Thenable<U>) | undefined' is not assignable to type '((value: boolean) => U | PromiseLike<U>) | null | undefined'.
Type '(value: boolean) => U | Thenable<U>' is not assignable to type '((value: boolean) => U | PromiseLike<U>) | null | undefined'.
Type '(value: boolean) => U | Thenable<U>' is not assignable to type '(value: boolean) => U | PromiseLike<U>'.
Type 'U | Thenable<U>' is not assignable to type 'U | PromiseLike<U>'.
Type 'Thenable<U>' is not assignable to type 'U | PromiseLike<U>'.
Type 'Thenable<U>' is not assignable to type 'PromiseLike<U>'.
Types of property 'then' are incompatible.
Type '<U>(onFulfilled?: ((value: U) => U | Thenable<U>) | undefined, onRejected?: ((error: any) => U | ...' is not assignable to type '<TResult1 = U, TResult2 = never>(onfulfilled?: ((value: U) => TResult1 | PromiseLike<TResult1>) |...'.
Types of parameters 'onFulfilled' and 'onfulfilled' are incompatible.
Type '((value: U) => TResult1 | PromiseLike<TResult1>) | null | undefined' is not assignable to type '((value: U) => TResult2 | Thenable<TResult2>) | undefined'.
Type 'null' is not assignable to type '((value: U) => TResult2 | Thenable<TResult2>) | undefined'.
Where exactly does the compiler think a TypeScripts ES6 Promise will return null
(if thats the actual error)?
And why do some libraries (bluebird, rsvp, ember, ...) use Thenable
instead of Promise
/PromiseLike
?
Ajv's Thenable
type declaration says that the second parameter to then
, typically called onRejected
, when called, must return the same type <U>
as the first onFulfilled
parameter. ES6 promises, and thus TypeScript's Promise
/PromiseLike
, have no such restriction.
For example, in this code:
const p1: PromiseLike<boolean> = /* ... */
const p2 = p1.then(() => true, () => 123)
TypeScript will (correctly) infer that p2 has type PromiseLike<number | boolean>
. With Ajv's Thenable
type declaration, the equivalent code will fail to compile, because 123 is not assignable to boolean.
The actual AJV JavaScript code seems to be returning normal Promises, so
it doesn't care about types. So this seems like a bug in AJV's TypeScript declarations to me... I don't know why AJV is not using TypeScript's built-in PromiseLike
here...