I wrote out `type MyReturnType<T> = T extends (...args: any[]) => infer R ?
Start by defining a generic type that uses a conditional type to check if the input extends a function signature, then use the infer keyword to capture the return type. Explain how this mirrors the built-in ReturnType<T> and discuss edge cases like overloads and any/never.
Pro tip: Mention that the built-in ReturnType<T> is implemented exactly this way in TypeScript's lib.es5.d.ts, showing you understand the standard library. Also, note that inferring from overloaded functions only captures the last overload, which is a common pitfall.
Declare a type alias that takes a type parameter T, e.g., type MyReturnType<T> = ...
Write a conditional type: T extends (...args: any) => infer R ? R : any. This checks if T is a function and infers its return type as R.
Decide on the fallback type when T is not a function (e.g., any, never, or unknown) and explain your choice.
Demonstrate usage with simple functions, async functions (returning Promise), and overloaded functions to show understanding of edge cases.
Explain that this is exactly how TypeScript's built-in ReturnType<T> works, and mention any differences (e.g., handling of overloads).
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.
Explain that TypeScript's `ReturnType` utility type resolves to the return type of the last overload signature, not a union of all overloads. Then clarify that this is because `ReturnType` uses conditional type inference against the function type, which only captures the final overload's signature.
Pro tip: Mention that you can manually create a union of return types by using a distributive conditional type over the overloads, but it requires extracting each signature—something `ReturnType` doesn't do out of the box.
Briefly explain what an overloaded function is in TypeScript: multiple call signatures with a single implementation.
State that `ReturnType<T>` uses `T extends (...args: any) => infer R ? R : any`, which infers from the last overload signature.
Provide a concrete example of an overloaded function and show what `ReturnType` resolves to, highlighting it's the last overload.
Explain why this matters (e.g., unexpected types) and how to get a union of all return types using custom conditional types.
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.
This one tripped me up more than I expected.
Explain that ReturnType extracts the return type of a function type, but for generic functions it resolves to the return type with type parameters replaced by their constraints (or unknown if unconstrained). Then discuss limitations such as loss of generic parameter relationships, inability to infer from a specific instantiation, and issues with overloaded functions.
Pro tip: Mention that you can often work around the limitation by using a helper type that captures the generic parameters, or by using instantiation expressions (TypeScript 4.7+) to get a more precise return type. This shows deep practical knowledge.
State that ReturnType<T> is a built-in utility type that extracts the return type of a function type T. It is defined as T extends (...args: any) => infer R ? R : any.
Explain that when T is a generic function, TypeScript infers R by substituting the type parameters with their constraints (or unknown if no constraint). For example, ReturnType<typeof identity> where identity<T>(x: T): T yields unknown if T is unconstrained.
Discuss that the inferred return type loses the relationship between input and output types; it becomes a concrete type (like unknown) rather than a generic one. Also, it cannot capture conditional return types that depend on the generic parameter.
Mention that to get a more precise return type for a specific instantiation, you can use instantiation expressions (e.g., ReturnType<typeof identity<string>>) or create a custom utility type that preserves generics.
Conclude that while ReturnType is useful for non-generic functions, for generic functions it may produce overly broad types, so it's important to be aware of these limitations when designing type-safe APIs.
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.
Start by clarifying that ReturnType extracts the return type of a function, so for an async function it yields Promise<T>. Then explain that to get the inner type T, you can use the Awaited utility type (TypeScript 4.5+) or manually infer it with a conditional type. Emphasize that understanding this is crucial for typing async operations correctly.
Pro tip: Mention that using Awaited is the modern, recommended approach and that it also handles nested promises and thenables, which is important for robust type definitions in real-world code.
Explain that ReturnType<T> extracts the return type of a function type T. For an async function, the return type is always a Promise, so ReturnType<typeof asyncFn> gives Promise<InnerType>.
State that the inner type is the resolved value of the promise, which is what the async function returns when awaited.
Describe that TypeScript 4.5 introduced the Awaited<T> utility type, which recursively unwraps promises and thenables to get the final resolved type.
If needed, demonstrate how to manually unwrap using conditional types: type Unwrap<T> = T extends Promise<infer U> ? U : T; and apply it to ReturnType.
Highlight why this matters: correctly typing async function results avoids type errors and ensures proper handling of resolved values in code.
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.