infer được dùng bên trong một conditional type để bắt giữ (trích xuất) một kiểu từ bên trong một kiểu khác vào một type variable mới mà bạn có thể dùng sau đó. Đó là pattern-matching cho kiểu.
<T> = T (infer U)[] ? U : ;
A = <[]>;
B = <[]>;
Đọc nó là: "nếu T khớp với pattern U[], hãy gán U cho bất kỳ kiểu phần tử nào và trả về nó." infer U khai báo một placeholder mà compiler điền vào bằng cách matching.
// kiểu đã resolve của một Promise
type Awaited2<T> = T extends Promise<infer R> ? R : T;
type R = Awaited2<Promise<User>>; // User
// kiểu trả về của một hàm (đây là cách ReturnType được xây dựng)
type MyReturn<T> = T extends (...args: any[]) => infer R ? R : never;
type X = MyReturn<() => number>; // number
// tham số đầu tiên của một hàm
type FirstArg<T> = T extends (a: infer A, ...rest: any[]) => any ? A : never;
type UnwrapBoth<T> =
T extends Promise<infer U> ? UnwrapBoth<U> : // đệ quy để unwrap các promise lồng nhau
T extends (infer E)[] ? E : T;
Bạn có thể dùng nhiều infer trong một pattern và thậm chí đệ quy.
infer là động cơ đứng sau các kiểu built-in như ReturnType, Parameters, Awaited, và InstanceType, cũng như đứng sau những phép màu của thư viện như suy ra kiểu response từ fetcher hay props từ component.
Nó cho phép code kiểu "mở ra" một kiểu phức tạp và lấy ra các phần bên trong — công cụ mạnh mẽ nhất để viết kiểu thích nghi theo các kiểu khác.