TypeScript infer 怎么用
在写代码的时候,你有没有遇过这种情况?比如要把函数返回值的类型、数组元素的类型,或者对象里某个属性的类型抽出来用,却不知道怎么弄——要是只靠手动定义新类型,不仅麻烦,还容易出错。这时候,TypeScript 里的 infer 就派上用场了。
infer 是 TypeScript 专门用来做“类型提取”的工具,简单说,它能让你在类型定义里,像在函数里拿参数值一样,把某个类型里藏着的子类型“抓出来”。它不能单独用,得和条件类型结合起来,就像“先判断类型结构对不对,对的话就把想要的类型取出来”。

先看个最常见的例子:提取函数的返回类型
假设你有个处理用户信息的函数:
`typescript
function getUser() {
return { name: "小明", age: 25 };
}
`
现在要写一个新函数,它的参数得和 getUser 的返回值类型一模一样,总不能手动写个 { name: string; age: number } 吧?这就可以用 infer 来取:
`typescript
type GetReturn<T> = T extends (...args: any) => infer R ? R : never;
type UserInfo = GetReturn<typeof getUser>;
// 这时候 UserInfo 就是 { name: string; age: number }
`
解释一下:T extends (...args: any) => infer R 的意思是“如果类型 T 是一个函数,那我就把它的返回类型塞给变量 R”,后面的 ? R : never 就是说“对的话就用 R,不对就用 never”。这样不管 getUser 怎么改返回值,UserInfo 都会自动跟着变,不用手动维护。
再学个实用的:提取数组的元素类型
如果你有个存商品的数组:const goods = [{ id: 1, name: "苹果" }, { id: 2, name: "香蕉" }],想单独拿到数组里每个元素的类型,也能用 infer:
`typescript
type GetArrayElement<T> = T extends (infer E)[] ? E : never;
type Good = GetArrayElement<typeof goods>;
// Good 就是 { id: number; name: string }
`
这里 T extends (infer E)[] 就是“如果 T 是个数组,不管数组里存的是什么,把里面的元素类型抓出来给 E”,再返回 E 就得到了元素类型。要是数组里还有数组(比如二维数组),用这个类型也能拿到最内层的元素,非常灵活。
还有个场景:提取对象的属性类型
有时候对象的属性是另一个类型,比如:
`typescript
const config = { theme: "dark", fontSize: 14 };
`
想提取 theme 属性的类型,不用单独定义,用 infer 也能做到:
`typescript
type GetPropType<T, K> = T extends { [key: string]: infer V } ? V extends K ? V : never : never;
type ThemeType = GetPropType<typeof config, "theme">;
// ThemeType 就是 "dark" 这个字面量类型
`
这个稍微复杂点,但逻辑和之前一样:先判断 T 是个键为字符串的对象,把属性值类型塞给 V,再看 K 是不是对象里存在的键,是的话就返回属性值类型。
infer 看起来是在玩类型,其实核心是“让类型也能像数据一样被提取复用”。平时写代码的时候,只要遇到“要从现有类型里拆出某部分用”的情况,就可以想想能不能用它——不用再手动复制粘贴类型,既省时间又能减少因为类型不一致导致的 bug。