Typescript中infer关键字的使用小结
<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">基本语法</a></li><li><a href="#_label1">主要使用场景</a></li><ul class="second_class_ul"><li><a href="#_lab2_1_0">1.获取函数返回类型</a></li><li><a href="#_lab2_1_1">2.获取函数参数类型</a></li><li><a href="#_lab2_1_2">3.获取数组/元组元素类型</a></li><li><a href="#_lab2_1_3">4.获取 Promise 的解析类型</a></li></ul><li><a href="#_label2">实际应用示例</a></li><ul class="second_class_ul"><li><a href="#_lab2_2_4">示例1:提取对象值类型</a></li><li><a href="#_lab2_2_5">示例2:提取构造函数实例类型</a></li><li><a href="#_lab2_2_6">示例3:递归解包嵌套 Promise</a></li></ul><li><a href="#_label3">使用注意事项</a></li><ul class="second_class_ul"><li><a href="#_lab2_3_7">1.只能用在条件类型的 extends 子句中</a></li><li><a href="#_lab2_3_8">2.多个 infer 可以同时使用</a></li><li><a href="#_lab2_3_9">3.协变位置 vs 逆变位置</a></li></ul><li><a href="#_label4">实战技巧</a></li><ul class="second_class_ul"><li><a href="#_lab2_4_10">1.类型守卫与 infer</a></li><li><a href="#_lab2_4_11">2.构建实用类型工具</a></li></ul><li><a href="#_label5">总结</a></li><ul class="second_class_ul"></ul></ul></div><p><code>infer</code> 是 TypeScript 中<strong>条件类型</strong>的一个关键字,主要用于<strong>在条件类型中进行类型推断</strong>。它允许我们在泛型条件类型中<strong>声明一个类型变量</strong>,然后从其他类型中<strong>推断出这个类型</strong>。</p><p class="maodian"><a name="_label0"></a></p><h2>基本语法</h2>
<div class="jb51code"><pre class="brush:js;">type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
</pre></div>
<p class="maodian"><a name="_label1"></a></p><h2>主要使用场景</h2>
<p class="maodian"><a name="_lab2_1_0"></a></p><h3>1.获取函数返回类型</h3>
<div class="jb51code"><pre class="brush:js;">// 内置的 ReturnType 实现原理
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
function foo(): string {
return "hello";
}
type FooReturn = MyReturnType<typeof foo>; // string
</pre></div>
<p class="maodian"><a name="_lab2_1_1"></a></p><h3>2.获取函数参数类型</h3>
<div class="jb51code"><pre class="brush:js;">// 获取第一个参数类型
type FirstParam<T> = T extends (first: infer P, ...rest: any[]) => any ? P : never;
// 获取所有参数类型(元组)
type Params<T> = T extends (...args: infer P) => any ? P : never;
function bar(x: number, y: string): void {}
type BarFirstParam = FirstParam<typeof bar>; // number
type BarParams = Params<typeof bar>; //
</pre></div>
<p class="maodian"><a name="_lab2_1_2"></a></p><h3>3.获取数组/元组元素类型</h3>
<p>typescript</p>
<div class="jb51code"><pre class="brush:js;">type ArrayElement<T> = T extends (infer U)[] ? U : never;
type StrArrayElement = ArrayElement<string[]>; // string
type NumArrayElement = ArrayElement<number[]>; // number
</pre></div>
<p class="maodian"><a name="_lab2_1_3"></a></p><h3>4.获取 Promise 的解析类型</h3>
<div class="jb51code"><pre class="brush:js;">type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
type PromiseString = Promise<string>;
type Unwrapped = UnwrapPromise<PromiseString>; // string
</pre></div>
<p class="maodian"><a name="_label2"></a></p><h2>实际应用示例</h2>
<p class="maodian"><a name="_lab2_2_4"></a></p><h3>示例1:提取对象值类型</h3>
<div class="jb51code"><pre class="brush:js;">type ValueOf<T> = T extends { : infer V } ? V : never;
type Obj = { a: number; b: string };
type Values = ValueOf<Obj>; // number | string
</pre></div>
<p class="maodian"><a name="_lab2_2_5"></a></p><h3>示例2:提取构造函数实例类型</h3>
<div class="jb51code"><pre class="brush:js;">type InstanceType<T> = T extends new (...args: any[]) => infer R ? R : any;
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
}
type AnimalInstance = InstanceType<typeof Animal>; // Animal
</pre></div>
<p class="maodian"><a name="_lab2_2_6"></a></p><h3>示例3:递归解包嵌套 Promise</h3>
<div class="jb51code"><pre class="brush:js;">type DeepUnwrapPromise<T> =
T extends Promise<infer U> ? DeepUnwrapPromise<U> : T;
type NestedPromise = Promise<Promise<string>>;
type Result = DeepUnwrapPromise<NestedPromise>; // string
</pre></div>
<p class="maodian"><a name="_label3"></a></p><h2>使用注意事项</h2>
<p class="maodian"><a name="_lab2_3_7"></a></p><h3>1.只能用在条件类型的 extends 子句中</h3>
<div class="jb51code"><pre class="brush:js;">// ✅ 正确
type Example1<T> = T extends Array<infer U> ? U : never;
// ❌ 错误:infer 不能单独使用
type Example2<T> = infer U; // 编译错误
</pre></div>
<p class="maodian"><a name="_lab2_3_8"></a></p><h3>2.多个 infer 可以同时使用</h3>
<div class="jb51code"><pre class="brush:js;">type Zip<T, U> = T extends
? U extends
? [, ...Zip<RestT, RestU>]
: []
: [];
type Result = Zip<, ['a', 'b']>; // [, ]
</pre></div>
<p class="maodian"><a name="_lab2_3_9"></a></p><h3>3.协变位置 vs 逆变位置</h3>
<div class="jb51code"><pre class="brush:js;">// infer 在协变位置(返回类型)
type GetReturnType<T> = T extends () => infer R ? R : never;
// infer 在逆变位置(参数类型)
type GetArgType<T> = T extends (arg: infer A) => any ? A : never;
</pre></div>
<p class="maodian"><a name="_label4"></a></p><h2>实战技巧</h2>
<p class="maodian"><a name="_lab2_4_10"></a></p><h3>1.类型守卫与 infer</h3>
<div class="jb51code"><pre class="brush:js;">function isPromise<T>(value: any): value is Promise<T> {
return value && typeof value.then === 'function';
}
async function handle<T>(input: T | Promise<T>): Promise<T> {
if (isPromise(input)) {
// 这里 input 被推断为 Promise<T>
return input;
}
return Promise.resolve(input);
}
</pre></div>
<p class="maodian"><a name="_lab2_4_11"></a></p><h3>2.构建实用类型工具</h3>
<div class="jb51code"><pre class="brush:js;">// 提取所有方法的返回类型
type MethodsReturnType<T> = {
: T extends (...args: any[]) => infer R ? R : never;
};
// 提取特定属性的类型
type PropType<T, K extends keyof T> = T extends { : infer V } ? V : never;
</pre></div>
<p class="maodian"><a name="_label5"></a></p><h2>总结</h2>
<p><code>infer</code> 的核心作用:<strong>在条件类型中提取未知类型的内部结构</strong>。它是 TypeScript 类型系统的高级特性,常用于:</p>
<ol><li><strong>类型提取</strong>:从已有类型中提取部分类型信息</li><li><strong>类型转换</strong>:将一个类型转换为另一种形式</li><li><strong>类型推导</strong>:根据上下文推导出具体类型</li><li><strong>工具类型创建</strong>:构建复杂的实用类型工具</li></ol>
<p>掌握 <code>infer</code> 的关键是多实践,从简单的函数返回类型提取开始,逐步应用到更复杂的类型操作中。</p>
頁:
[1]