I noticed an interesting (possibly hacking) part in TypeScript’s lib.d.ts
:
interface PromiseConstructor {
/* ... */
/**
* Creates a Promise that is resolved with an array of results when all of the provided Promises
* resolve, or rejected when any Promise is rejected.
* @param values An array of Promises.
* @returns A new Promise.
*/
all<T extends readonly unknown[] | []>(values: T): Promise<{ -readonly [P in keyof T]: Awaited<T[P]>; }>;
/* ... */
}
Everything seems normal except for the part where T extends readonly unknown[]
is written as T extends readonly unknown[] | []
. This looks strange because []
extends readonly unknown[]
, so readonly unknown[]
should already cover []
. I later realized that this allows TS to infer the tuple type:
const f = <T extends readonly unknown[] | []>(x: T): T => x;
const test_0 = f([42, "foo"]);
// ^?: [number, string]
Without the | []
, it doesn’t work:
const f = <T extends readonly unknown[]>(x: T): T => x;
const test_0 = f([42, "foo"]);
// ^?: (number | string)[]
The relevant GitHub commit I found is this one.
The mechanism behind this seems quite magical, and I’m curious if anyone can explain the specifics of how it works.