The infer keyword can only appear inside the condition of a conditional type. It instructs TypeScript to infer — extract — a type from that position and bind it to a local type variable that you can reference in the true branch.
infer chỉ có thể xuất hiện trong mệnh đề điều kiện của một conditional type. Nó yêu cầu TypeScript 'suy ra' (trích xuất) một kiểu từ vị trí đó và gán cho một biến kiểu cục bộ mà bạn có thể sử dụng trong nhánh true.
1// Without infer you can only check a type, not capture part of it.2// With infer you capture and name an inner type on the fly.34type Unwrap<T> = T extends Promise<infer Inner> ? Inner : T;56type A = Unwrap<Promise<string>>; // string7type B = Unwrap<number>; // number (falls through to false branch)The variable Inner exists only within the true branch scope. TypeScript determines its type by solving what Inner must be for the condition T extends Promise<Inner> to hold.
Biến Inner chỉ tồn tại trong phạm vi của nhánh true. TypeScript tự xác định kiểu cho Inner dựa trên những gì cần khớp để điều kiện T extends Promise<Inner> thỏa mãn.
The most canonical use of infer is extracting a function's return type — this is exactly how the built-in ReturnType<T> is constructed.
Trường hợp sử dụng kinh điển nhất của infer là trích xuất kiểu trả về của một hàm — đây chính xác là cách ReturnType<T> được xây dựng trong thư viện chuẩn.
1// Built-in equivalent — implemented with infer2type MyReturnType<T extends (...args: unknown[]) => unknown> =3 T extends (...args: unknown[]) => infer R ? R : never;45function greet(name: string): string {6 return `Hello, ${name}`;7}89async function fetchUser(id: number): Promise<{ id: number; name: string }> {10 return { id, name: "Alice" };11}1213type GreetReturn = MyReturnType<typeof greet>; // string14type FetchReturn = MyReturnType<typeof fetchUser>; // Promise<{ id: number; name: string }>1516// Combine with Awaited to unwrap the Promise too17type ResolvedUser = Awaited<MyReturnType<typeof fetchUser>>;18// { id: number; name: string }You can equally extract a function's parameter types. The standard library ships Parameters<T>, but you can build specialised variants yourself.
Tương tự, bạn có thể trích xuất kiểu của các tham số hàm. Thư viện chuẩn cung cấp Parameters<T>, nhưng bạn cũng có thể tự xây dựng các biến thể chuyên dụng.
1// Built-in equivalent2type MyParameters<T extends (...args: unknown[]) => unknown> =3 T extends (...args: infer P) => unknown ? P : never;45// Extract only the first parameter6type FirstParameter<T extends (...args: unknown[]) => unknown> =7 T extends (first: infer F, ...rest: unknown[]) => unknown ? F : never;89// Extract the last parameter10type LastParameter<T extends (...args: unknown[]) => unknown> =11 T extends (...args: [...infer _, last: infer L]) => unknown ? L : never;1213function createUser(id: number, name: string, role: "admin" | "user") {}1415type AllParams = MyParameters<typeof createUser>; // [number, string, "admin" | "user"]16type First = FirstParameter<typeof createUser>; // number17type Last = LastParameter<typeof createUser>; // "admin" | "user"...infer _ là cú pháp tuple rest inference — dấu gạch dưới là tên biến hợp lệ mà TypeScript bỏ qua. Đây là kỹ thuật tiêu chuẩn để 'tiêu thụ' các phần không cần thiết của một tuple.
infer is flexible with container types. You can extract an array's element type, a Promise's resolved value, or any generic type argument.
infer rất linh hoạt với các kiểu container. Bạn có thể trích xuất phần tử của mảng, giá trị được resolve của Promise, hoặc bất kỳ kiểu tham số generic nào.
1// Unwrap one level of array2type UnpackArray<T> = T extends (infer Item)[] ? Item : T;34// Recursively unwrap nested arrays5type DeepUnpackArray<T> = T extends (infer Item)[]6 ? DeepUnpackArray<Item>7 : T;89// Built-in Awaited<T> — simplified version10type MyAwaited<T> = T extends PromiseLike<infer Resolved>11 ? MyAwaited<Resolved>12 : T;1314type A = UnpackArray<string[]>; // string15type B = UnpackArray<number[][]>; // number[] (one level)16type C = DeepUnpackArray<number[][][]>; // number (fully unwrapped)17type D = MyAwaited<Promise<Promise<Date>>>; // DateTypeScript 4.5+ allows infer inside template literal types, enabling string-level parsing at the type layer.
TypeScript 4.5+ cho phép dùng infer bên trong các kiểu template literal, giúp bạn phân tích cú pháp chuỗi ở cấp độ kiểu.
1// Extract the route method prefix: "GET /users" → "GET"2type ExtractMethod<T extends string> =3 T extends `${infer Method} ${string}` ? Method : never;45// Split a dot-separated path: "a.b.c" → ["a", "b.c"] heads6type Head<T extends string> =7 T extends `${infer H}.${string}` ? H : T;89type Tail<T extends string> =10 T extends `${string}.${infer T}` ? T : never;1112// Extract event name from "on<Event>" pattern13type EventName<T extends string> =14 T extends `on${infer E}` ? Uncapitalize<E> : never;1516type M = ExtractMethod<"GET /users">; // "GET"17type H = Head<"user.profile.avatar">; // "user"18type TL = Tail<"user.profile.avatar">; // "profile.avatar"19type E = EventName<"onClick">; // "click"20type E2 = EventName<"onMouseEnter">; // "mouseEnter"A single conditional type can contain multiple infer variables simultaneously, letting you extract several parts of a complex type in one step.
Một conditional type có thể chứa nhiều biến infer cùng lúc. Điều này cho phép bạn trích xuất nhiều phần của một kiểu phức tạp trong một bước duy nhất.
1// Swap the first and second argument of a two-argument function2type SwapArgs<T extends (a: unknown, b: unknown) => unknown> =3 T extends (a: infer A, b: infer B) => infer R4 ? (a: B, b: A) => R5 : never;67// Extract key and value types from a Map8type MapKV<T> = T extends Map<infer K, infer V>9 ? { key: K; value: V }10 : never;1112// Destructure a Promise-returning function into its partsinfer variable appears at both covariant and contravariant positions, TypeScript intersects or unions the inferred types depending on variance. Use distinct variable names if you want independent captures.Khi cùng một biến infer xuất hiện nhiều lần ở các vị trí contravariant và covariant, TypeScript sẽ giao nhau (intersect) hoặc hợp nhất (union) các kiểu tùy theo vị trí. Hãy dùng các tên biến khác nhau nếu bạn muốn chúng độc lập.
infer is only valid inside the condition clause of a conditional typeinfer chỉ hợp lệ trong mệnh đề điều kiện của conditional type
Nó đặt tên cho một phần của kiểu để bạn dùng lại trong nhánh true
ReturnType, Parameters, Awaited trong thư viện chuẩn đều được xây dựng bằng infer
Bạn có thể dùng nhiều biến infer trong một điều kiện để trích xuất nhiều phần cùng lúc
Template literal inference cho phép phân tích cú pháp chuỗi ở cấp độ kiểu
Recursive infer (như trong Awaited) xử lý được các kiểu lồng nhau tùy ý