extends). But what if you don’t just want to evaluate a condition, but actually extract a piece of the type you are evaluating? The infer keyword allows you to declare a variable inside a conditional type, unlocking deep pattern matching.1. How infer Works#
The infer keyword can only be used inside the extends clause of a conditional type.
It tells the TypeScript compiler: “Try to match this structural pattern. If it matches, extract that specific structural piece and assign it to a new type variable.”
Rebuilding ReturnType<T>#
Let’s rebuild the built-in ReturnType<T> utility that we used in the Intermediate module. We want to extract whatever a function returns.
// 1. We check if T matches the pattern of a function: T extends (...args: any[]) => ...
// 2. We replace the return 'any' with 'infer R'.
// 3. If T is a function, return the inferred variable R. If not, return never.
type CustomReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
function createSession() {
return { token: "123", expires: 3600 };
}
// 🟢 Extracts the exact return signature!
type Session = CustomReturnType<typeof createSession>;
/* Inferred Type:
{
token: string;
expires: number;
}
*/2. Extracting Object Properties#
You can use pattern matching to extract the type of a specific property from an object, even if you don’t know the full shape of the object.
Imagine an event-driven system where actions optionally have a payload property. We want to write a utility that extracts the payload type, and returns never if there is no payload.
// Pattern Match: Does T have a 'payload' property? If so, extract its type into 'P'.
type ExtractPayload<T> = T extends { payload: infer P } ? P : never;
type Action1 = { type: "LOGIN"; payload: { userId: string } };
type Action2 = { type: "LOGOUT" };
type P1 = ExtractPayload<Action1>;
// Inferred Type: { userId: string }
type P2 = ExtractPayload<Action2>;
// Inferred Type: never (The pattern did not match because 'payload' is missing)
3. Parsing Template Literals#
One of the most jaw-dropping features of modern TypeScript is the ability to use infer inside Template Literal Types to parse and extract parts of a string!
Let’s say we have an authentication system that requires a strictly formatted Bearer <token> string. We want to extract just the token part for our database query.
// Pattern Match: Does T start with "Bearer " followed by any string?
// If so, extract the rest of the string into 'Token'.
type ExtractBearerToken<T> = T extends `Bearer ${infer Token}` ? Token : never;
type AuthHeader = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
type TokenOnly = ExtractBearerToken<AuthHeader>;
// Inferred Type: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
Advanced Parsing: Route Parameters#
You can chain infer declarations to build fully-fledged route parsers that extract multiple URL parameters simultaneously!
type ExtractRouteParams<T> =
T extends `/users/${infer UserId}/posts/${infer PostId}`
? { userId: UserId; postId: PostId }
: never;
type Params = ExtractRouteParams<"/users/99/posts/1024">;
/* Inferred Type:
{
userId: "99";
postId: "1024";
}
*/The infer keyword elevates TypeScript from a simple structural validation tool into a powerful, Turing-complete data extractor at compile time!
Summary & Next Steps#
In this episode:
- We learned that
inferdeclares type variables insideextendsclauses. - We rebuilt
ReturnType<T>to extract function outputs. - We used structural pattern matching to extract object payloads (
infer P). - We parsed Template Literal strings to extract JWT tokens and URL route parameters (
${infer Token}).
In Episode 45: Inferring Promises (Awaited), we will look at how to use infer recursively to unwrap Promises!

