Description
Bug Report
π Search Terms
contextual typing, generic, async, return type, union
π Version & Regression Information
This is the behavior in every version I tried, and I reviewed the FAQ
β― Playground Link
TS playground (latest)
TS playground (nightly)
π» Code
declare class StateMachine<T> {
onDone: (a: T) => void;
}
declare function createMachine<T>(implementations: {
services: Record<string, () => Promise<T> | StateMachine<T>>;
}): void;
// this is close to my original issue found in the real-world in XState
createMachine<{ count: number }>({
services: {
test: async () => Promise.reject("some err"),
async test2() {
return Promise.reject("some err");
},
},
});
// this is an additional test case I've figured out that behaves in a similar way.
function fn1(): () => Promise<{ count: number }> | StateMachine<{ count: number }> {
return async () => Promise.reject('some err')
}
π Actual behavior
Both tests fail to compile and the reported error looks bizzare(-ish):
Type '() => Promise<{ count: number; } | StateMachine<{ count: number; }>>' is not assignable to type '() => Promise<{ count: number; }> | StateMachine<{ count: number; }>'.
Type 'Promise<{ count: number; } | StateMachine<{ count: number; }>>' is not assignable to type 'Promise<{ count: number; }> | StateMachine<{ count: number; }>'.
Type 'Promise<{ count: number; } | StateMachine<{ count: number; }>>' is not assignable to type 'Promise<{ count: number; }>'
For some reason, the return type here didn't narrow the contextual union to include only Promise(-like?) members and dragged the whole Awaited<Union>
to the computed contextual type. And this has caused an assignability problem.
Note that this "only" happens with Promise.reject
, it's not reproducible with Promise.resolve
and other similar types. My guess is that it's because Promise.reject
contains a generic only at the return type position and this is what makes this issue manifest somehow.
π Expected behavior
No error should be reported because this is valid code and it looks like sufficient information has been provided in the context for this to be narrowed down properly~.
While looking into this problem I've poked around the internals of TS and figured out that this might be a potential fix for this issue: #47683