This particular example functions as intended without experiencing literal type widening - the generic function route()
is called without specifying its generic type parameter S
:
route('T', async function () {
return { status: 5, data: {r: 'm'} };
});
The compiler infers S
from the types of the actual arguments passed.
Since the first argument is a literal 'T'
, it determines that S
should be a literal type 'T'
.
As a result, the return type of the second argument, () => Promise<Def[S]>
, becomes fixed to the object literal type defined as Def['T']
. The compiler does not need to infer the return type for the async function; it only checks that it conforms to Def['T']
(which it does).
In contrast, a more complex code scenario may disrupt the type inference process due to an index signature in ApiDefBase
, potentially impacting the resolution of Path
. If a similar index signature is added to the simple example, you could encounter the same error:
type DefBase = { [p in string]: {}}
interface Def extends DefBase {
'T': { status: 5, data: {r: 'm'}},
}
function route<S extends keyof Def>
(route: S, handler: () => Promise<Def[S]>) { }
route('T', async function () {
return { status: 5, data: {r: 'm'} };
});
Argument of type '() => Promise<{ status: number; data: { r: string; }; }>' is not assignable to parameter of type '() => Promise<{ status: 5; data: { r: "m"; }; }>'.
Type 'Promise<{ status: number; data: { r: string; }; }>' is not assignable to type 'Promise<{ status: 5; data: { r: "m"; }; }>'.
Type '{ status: number; data: { r: string; }; }' is not assignable to type '{ status: 5; data: { r: "m"; }; }'.
Types of property 'status' are incompatible.
Type 'number' is not assignable to type '5'.
The reason behind this disruption caused by adding an index signature to the type inference remains unclear to me at this time.