JavaScript 类型体操:TypeScript 高级类型,让你的代码像太极一样优雅!
各位观众,晚上好!欢迎来到今天的 "TypeScript 类型体操" 讲座。今天,我们不谈枯燥的类型定义,而是要让大家感受一下类型系统的力量,就像练太极一样,四两拨千斤,用看似简单的技巧,解决复杂的问题。 准备好了吗?让我们一起走进 TypeScript 高级类型的世界,体验一下类型体操的魅力!💪
一、开场:什么是类型体操?为什么要练?
你可能会好奇:什么是“类型体操”?听起来像某种健身运动。没错,它确实是一种“健身运动”,只不过锻炼的是你的大脑,提升的是你的类型编程能力。
简单来说,类型体操就是利用 TypeScript 提供的各种高级类型特性(比如 Conditional Types, Mapped Types, etc.)来玩转类型,对类型进行转换、计算、推断,最终得到我们想要的类型结果。
为什么要练?
- 提升代码质量: 更精确的类型定义可以避免运行时错误,让你的代码更加健壮。
- 增强代码可读性: 通过清晰的类型定义,可以让其他人更容易理解你的代码意图。
- 提高代码复用性: 通过泛型和类型体操,可以编写更通用、更灵活的代码。
- 解锁高级框架和库的源码: 许多流行的前端框架和库,比如 React、Vue、Angular,都大量使用了 TypeScript 高级类型。掌握类型体操,才能更好地理解它们的源码,甚至参与贡献。
- 面试加分项: 毫不夸张地说,掌握类型体操,是高级前端工程师的必备技能。面试官会通过考察你对类型体操的理解,来判断你对 TypeScript 的掌握程度。
总之,类型体操就像武林秘籍,练成之后,不仅可以让你在代码世界里更加游刃有余,还能让你在面试场上脱颖而出!😎
二、热身:回顾 TypeScript 基础类型
在开始高难度动作之前,我们需要先热身一下,回顾一下 TypeScript 的基础类型:
boolean
: 布尔值,true
或false
。number
: 数字,包括整数和浮点数。string
: 字符串。null
: 空值。undefined
: 未定义。symbol
: ES6 新增的原始数据类型,表示独一无二的值。object
: 对象。array
: 数组。tuple
: 元组,固定长度和类型的数组。enum
: 枚举,一组命名的常量。any
: 任意类型,放弃类型检查,尽量避免使用。unknown
: 未知类型,比any
更安全,需要进行类型断言或类型收窄才能使用。void
: 没有返回值。never
: 永远不会到达的类型,通常用于抛出异常或无限循环的函数。
这些基础类型就像我们练武的基本功,只有打好基础,才能更好地学习高级类型。
三、正餐:Conditional Types(条件类型)
现在,让我们进入今天的正餐:Conditional Types(条件类型)。条件类型就像编程界的“如果…那么…否则…”语句,可以根据不同的类型条件,返回不同的类型结果。
1. 基本语法:
T extends U ? X : Y
T extends U
:判断类型T
是否可以赋值给类型U
。? X
:如果T extends U
为真,则返回类型X
。: Y
:如果T extends U
为假,则返回类型Y
。
2. 示例:判断类型是否为 string
type IsString<T> = T extends string ? true : false;
type Result1 = IsString<string>; // true
type Result2 = IsString<number>; // false
在这个例子中,IsString<T>
接收一个类型参数 T
,如果 T
可以赋值给 string
,则返回 true
,否则返回 false
。
3. infer
关键字:类型推断的利器
infer
关键字是条件类型中最强大的工具之一,它可以用来推断类型。
示例:获取数组元素的类型
type ElementType<T> = T extends (infer U)[] ? U : never;
type Result3 = ElementType<number[]>; // number
type Result4 = ElementType<string>; // never
在这个例子中,ElementType<T>
接收一个类型参数 T
,如果 T
是一个数组类型,则使用 infer U
推断数组元素的类型,并将推断结果赋值给 U
,然后返回 U
。如果 T
不是一个数组类型,则返回 never
。
4. 分布式条件类型(Distributive Conditional Types)
当条件类型中的类型参数是一个联合类型时,TypeScript 会将条件类型应用到联合类型的每个成员上,然后将结果组合成一个新的联合类型。
示例:从联合类型中排除 null
和 undefined
type NonNullable<T> = T extends null | undefined ? never : T;
type Result5 = NonNullable<string | number | null | undefined>; // string | number
在这个例子中,NonNullable<T>
接收一个类型参数 T
,如果 T
是 null
或 undefined
,则返回 never
,否则返回 T
。当 T
是 string | number | null | undefined
时,TypeScript 会将条件类型应用到每个成员上:
string extends null | undefined ? never : string
=>string
number extends null | undefined ? never : number
=>number
null extends null | undefined ? never : null
=>never
undefined extends null | undefined ? never : undefined
=>never
然后将结果组合成一个新的联合类型 string | number | never | never
,最终简化为 string | number
。
表格总结:Conditional Types 的关键点
| 特性 | 描述 | 示例