If you want to create your own utility types, you can follow a similar approach to how the ReturnType
type is implemented. Instead of inferring the entire return type, focus on inferring the type arguments for the AsyncGenerator
and Generator
generic types. These types represent what generator and async generator functions return in TypeScript:
type GenYieldType<T extends (...args: any) => Generator<any, any, any>> =
T extends (...args: any) => Generator<infer R, any, any> ? R : never;
type AsyncGenYieldType<T extends (...args: any) => AsyncGenerator<any, any, any>> =
T extends (...args: any) => AsyncGenerator<infer R, any, any> ? R : never
Let's put it to the test:
async function* foo() { yield "a"; yield "b"; }
type FooYield = AsyncGenYieldType<typeof foo>
// ^? type FooYield = "a" | "b"
function* bar() { yield "c"; yield "d"; }
type BarYield = GenYieldType<typeof bar>
// ^? type BarYield = "c" | "d"
Looks like everything is working as expected.
Check out the playground link for more code examples