ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

TypeScript 条件类型中的 infer:从类型中提取类型的核心机制

TypeScript 条件类型中的 infer:从类型中提取类型的核心机制 文档教程【免费下载链接】typescript-bookThe Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.项目地址https://gitcode.com/gh_mirrors/typ/typescript-book点击查看免费下载infer是 TypeScript 条件类型中用于推断并提取类型的核心关键字它允许你从某个依赖类型参数的结构中反向抽取出嵌套的类型从而写出高度灵活、可复用的类型工具。本文以 The Concise TypeScript Book 的 infer Type Inference in Conditional Types 一章为核心结合书中条件类型、类型操作与内置工具类型的相关章节系统讲解infer的语法、推断规则与实战模式读完你即可自己编写ReturnType、Parameters级别的类型工具函数。前置知识infer 生存的土壤——条件类型infer不能脱离条件类型单独使用因此理解它之前必须先掌握条件类型。书中 Conditional Types 一章给出的定义是条件类型是一种依赖于某个条件来创建类型的方式结果类型由条件判断的结果决定使用extends关键字配合三元运算符在两个类型之间二选一type IsArrayT T extends any[] ? true : false; const myArray [1, 2, 3]; const myNumber 42; type IsMyArrayAnArray IsArraytypeof myArray; // Type true type IsMyNumberAnArray IsArraytypeof myNumber; // Type false这里的条件判断T extends any[]是类型层面的结构匹配如果T可以赋值给any[]就取true分支否则取false分支。而infer要解决的正是在匹配成功的分支里把匹配到的具体类型捕获出来——这是条件类型从判断真假升级为提取结构的关键一步。infer 的基本语法与工作原理书中 infer Type Inference in Conditional Types 一章对infer的定义是infer关键字用于条件类型中从某个依赖于泛型参数的类型中推断提取该泛型参数的类型从而允许你编写更灵活、可复用的类型定义。核心示例是提取数组元素的类型type ElementTypeT T extends (infer U)[] ? U : never; type Numbers ElementTypenumber[]; // number type Strings ElementTypestring[]; // string逐行拆解这个例子T extends (infer U)[]把T与某种元素类型的数组这个结构模式做匹配(infer U)[]中的infer U是一个占位符它声明这里应该有一个类型叫U具体是什么由编译器在匹配时推断当T number[]时编译器把number[]与(infer U)[]对齐自然推出U number于是走真分支返回number当传入的类型不是数组例如ElementTypenumber时匹配失败走假分支返回never。可以看到infer让条件类型第一次具备了模式匹配 变量绑定的能力这与函数式语言中的解构/模式匹配思想一脉相承。深入原理infer 的推断规则要准确使用infer需要把握以下几条核心规则。1. infer 只能出现在条件类型的 extends 子句中infer声明的位置仅限于T extends ... ? ... : ...的extends右侧的模式内。它无法在普通类型别名、接口或函数签名中单独声明。它的作用域就是当前这一条条件类型的真分支?之后的类型。2. 推断位置决定提取结果infer放在模式中的哪个位置就决定它提取的是哪一部分类型// 提取函数返回值类型 type ReturnT T extends (...args: any[]) infer R ? R : never; // 提取函数参数类型元组形式 type ParamsT T extends (...args: infer P) any ? P : never; // 提取 Promise 内部类型 type UnwrapT T extends Promiseinfer U ? U : never;3. 一个条件类型可以声明多个 infer 变量当模式包含多个需要捕获的结构时可以并列声明多个infer编译器会分别推断type SwapT T extends [infer A, infer B] ? [B, A] : never; type Swapped Swap[string, number]; // [number, string]元组、函数参数列表、对象结构的组合都可以作为多变量推断的载体。4. 推断失败时进入 false 分支当传入的类型无法与模式匹配时整个条件类型的结果是extends之后的false分支习惯上写never。因此never分支是infer工具类型的失败信号调用方可以用它表达该类型不具备此结构。实战模式一手写 ReturnType——提取函数返回值书中 Type Manipulation 一章演示了同样的思路用infer提取函数参数类型type ExtractParamT T extends (param: infer P) any ? P : never; type MyFunction (name: string) number; type ParamType ExtractParamMyFunction; // string沿着这个思路可以自己实现 TypeScript 内置的ReturnTypeT它提取函数类型的返回值类型type MyReturnTypeT T extends (...args: any[]) infer R ? R : never; type Func (name: string) number; type MyType MyReturnTypeFunc; // number...args: any[]表示接受任意参数infer R捕获返回值。注意any[]在这里只是占位参数的具体类型不影响返回值推断。实战模式二提取函数参数与构造器参数把infer放到参数列表位置即可拿到参数的元组类型type MyParametersT T extends (...args: infer P) any ? P : never; type Func (a: string, b: number) void; type MyType MyParametersFunc; // [a: string, b: number]元组类型保留了参数的顺序还可以配合解构进一步提取第一个参数type FirstParamT T extends (first: infer F, ...rest: any[]) any ? F : never; type F FirstParam(name: string, age: number) void; // string对于类则用infer捕获构造函数的参数列表。书中 Type Manipulation 一节的ConstructorParametersT示例展示了这一用法class Person { constructor( public name: string, public age: number ) {} } type PersonConstructorParams ConstructorParameterstypeof Person; // [name: string, age: number] const params: PersonConstructorParams [John, 30]; const person new Person(...params); console.log(person); // Person { name: John, age: 30 }实战模式三递归解包——Promise 与嵌套数组infer与递归条件类型组合可以实现无限层解包。书中 Others 一章列有 Recursive Conditional Types递归条件类型这一主题其典型应用就是深度展开 Promise 与数组// 递归解开 Promise type DeepAwaitedT T extends Promiseinfer U ? DeepAwaitedU : T; type A DeepAwaitedPromisePromisestring; // string // 递归展平数组 type FlattenT T extends (infer U)[] ? FlattenU : T; type Nested Flattennumber[][][]; // number递归的关键在于真分支里再次引用FlattenU/DeepAwaitedU直到U不再是数组或 Promise 时落入 false 分支返回自身。TypeScript 4.1 支持递归条件类型使得这类工具既可以安全收敛又能保持类型层面的完全展开。内置的AwaitedT正是这一思路的官方实现见 Type Manipulationtype A AwaitedPromisestring; // string与分发条件类型的协同当infer工具类型传入联合类型时行为取决于条件类型是否具备分发性。书中 Distributive Conditional Types 一章指出当裸类型参数T直接出现在T extends ...左侧时条件类型会逐个成员分发type NullableT T extends any ? T | null : never; type NumberOrBool number | boolean; type NullableNumberOrBool NullableNumberOrBool; // number | boolean | null而infer工具类型通常写成T extends (infer U)[]这种形式——T此时被包在模式内部不具备分发性联合类型会作为一个整体参与匹配type ElementTypeT T extends (infer U)[] ? U : never; type Both ElementTypenumber[] | string[]; // number | string并集结果理解分发与整体匹配的差别是正确设计高阶infer工具类型的前提。内置条件类型中的 infer 应用很多 TypeScript 内置工具类型本质上都是infer的封装。Predefined Conditional Types 一章列出的内置条件类型中以下这些直接依赖infer实现ReturnTypeType提取函数类型的返回值...args: any[] infer RParametersType提取函数类型的参数元组...args: infer P anyAwaitedType递归解开 PromisePromiseinfer UConstructorParametersType提取构造函数参数new (...args: infer P) anyInstanceTypeType提取类实例类型。书中 Type Manipulation 的 Utility Types 一节对上述工具给出了完整示例例如type Func (name: string) number; type MyType ReturnTypeFunc; // number把内置工具的官方实现与自己用infer手写的版本对照学习是理解类型系统底层机制的捷径。常见陷阱与注意事项不要忘记 never 分支infer匹配失败时必须返回一个失败类型规范写法是never它会在联合、分发等场景中被自动吸收是最安全的哨兵值。infer 推断的是结构而非值infer只能出现在类型位置用于捕获类型结构不能用于捕获运行时的值。避免无意义的 infer如果infer U在模式中从未被使用编译器会给出错误如infer声明了却未引用应直接删除该声明。递归工具注意收敛条件递归infer工具必须保证递归深度随类型结构严格递减否则会产生类型实例化过深Type instantiation is excessively deep的编译错误。匹配顺序与优先级当模式中存在多个可匹配位置时例如元组中的 rest 参数推断结果取决于 TypeScript 的固定推断顺序需要精确控制时可借助元组的 rest 元素...infer Rest显式划分边界。本仓库对示例的编译验证机制作为《The Concise TypeScript Book》的配套仓库本书对文中所有 TypeScript 代码示例都有工程化的质量保障infer相关示例同样如此tools/compile.ts 会从每个 Markdown 文档中提取所有 typescript 代码块使用ts.createProgram建立编译程序并收集诊断信息见compileAndReport与logReports确保书中的类型示例——包括ElementTypeT这类infer工具——在tsc下真实可编译、可运行个别无法独立编译的示例通过!-- skip --注释显式跳过tools/verify_codeblocks.py 逐一校验每个 Markdown 文件中代码围栏 与 ~~~的开闭配对防止示例因围栏错乱而失效。这意味着你完全可以把书中以及本文的infer示例直接复制到自己的tsconfig.json环境中运行验证。你也可以在 Table of Contents 中定位到本章的上下文位置按 Conditional Types → Distributive Conditional Types → infer Type Inference in Conditional Types → Predefined Conditional Types 的顺序循序渐进地学习完整链路。小结infer把 TypeScript 的条件类型从二选一的开关升级为模式匹配引擎T extends (infer U)[] ? U : never一句即可提取数组元素类型稍加组合便能实现ReturnType、Parameters、Awaited、Flatten等强大的类型工具。掌握它之后你可以为项目编写从任意函数提取参数递归解包异步结果从配置类型推导事件类型等高阶类型抽象让类型系统真正成为可编程的表达层。赞分享文档教程【免费下载链接】typescript-bookThe Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.项目地址https://gitcode.com/gh_mirrors/typ/typescript-book点击查看免费下载相关推荐esp-idf 组件解析bootloader_support —— 引导加载器与应用共用的底层基础设施esp idf 组件解析bootloader_support —— 引导加载器与应用共用的底层基础设施 导读 本篇文章聚焦乐鑫官方物联网开发框架ESP ID文档教程从源码到趣味duck.nvim不到100行代码如何实现鸭子漫步效果从源码到趣味duck.nvim不到100行代码如何实现鸭子漫步效果 duck.nvim是一款轻量级Neovim插件仅用不到100行代码就实现了让鸭子在编辑ReactPy中的TypeScript条件类型高级类型技巧ReactPy中的TypeScript条件类型高级类型技巧 在ReactPy开发中TypeScript的类型系统为我们提供了强大的类型检查和代码提示能力。其前端UI组件上一篇STAR终极指南快速掌握RNA-seq比对核心技术下一篇3 分钟装好 Humanizer消除 AI 写作痕迹让稿件不再一眼假创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表