首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
01 | 重塑“类型思维”
02 | 类型基础(1):强类型与弱类型
03 | 类型基础(2):动态类型与静态类型
04 | 编写你的第一个TypeScript程序
05 | 基本类型
06 | 枚举类型
07 | 接口(1):对象类型接口
08 | 接口(2):函数类型接口
09 | 函数相关知识点梳理
10 | 类(1):继承和成员修饰符
11 | 类(2):抽象类与多态
12 | 类与接口的关系
13 | 泛型(1):泛型函数与泛型接口
14 | 泛型(2):泛型类与泛型约束
15 | 类型检查机制(1):类型推断
16 | 类型检查机制(2):类型兼容性
17 | 类型检查机制(3):类型保护
18 | 高级类型(1):交叉类型与联合类型
19 | 高级类型(2):索引类型
20 | 高级类型(3):映射类型
21 | 高级类型(4):条件类型
22 | ES6与CommonJS的模块系统
23 | 使用命名空间
24 | 理解声明合并
25 | 如何编写声明文件
26 | 配置tsconfig.json(1):文件选项
27 | 配置tsconfig.json(2):编译选项
28 | 配置tsconfig.json(3):工程引用
29 | 编译工具:从ts-loader到Babel
30 | 代码检查工具:从TSLint到ESLint
31 | 使用Jest进行单元测试
32 | 创建项目
33 | 组件与类型(1):函数组件与类组件
34 | 组件与类型(2):高阶组件与Hooks
35 | 事件处理与数据请求
36 | 列表渲染与路由
37 | Redux与类型
38 | 搭建服务端开发环境
39 | 列表的CRUD
40 | 导出Excel
41 | 搭建Vue开发环境
42 | 组件封装
43 | 组件发布
44 | 共存策略
45 | 宽松策略
46 | 严格策略
当前位置:
首页>>
技术小册>>
TypeScript开发实战
小册名称:TypeScript开发实战
### 19 | 高级类型(2):索引类型 在TypeScript的深度探索之旅中,高级类型无疑是提升代码表达力、增强类型安全性的重要工具。继前一章节对映射类型、条件类型等高级特性的介绍后,本章我们将聚焦于“索引类型”(Indexed Types),这一特性允许我们基于对象的索引签名来操作类型,实现更为灵活和强大的类型变换。索引类型不仅限于数组和对象的键值对操作,更能在泛型编程中展现出其独特的魅力。 #### 一、索引类型基础 在TypeScript中,索引类型主要指的是通过索引签名(Index Signature)来定义的类型。索引签名允许我们为对象类型或数组类型指定一个索引的类型以及该索引对应的值的类型。对于对象而言,这通常意味着我们可以定义一个属性名(索引)到属性值(类型)的映射;而对于数组,则是一种特殊的索引签名,其索引为数字类型,表示数组元素的索引和类型。 **示例**: ```typescript interface StringMap { [key: string]: number; } const myMap: StringMap = { 'apple': 1, 'banana': 2, 'cherry': 3, }; // 错误:属性名必须是字符串,且值必须是数字 // myMap['date'] = new Date(); ``` 在上述示例中,`StringMap`接口定义了一个索引签名,表明任何字符串类型的键都将映射到一个数字类型的值上。 #### 二、索引访问类型(Indexed Access Types) 索引访问类型允许我们通过类型操作来访问对象的属性类型或数组元素的类型。这种类型在泛型编程中尤为有用,因为它允许我们根据泛型参数动态地获取或设置类型。 **语法**: ```typescript type TypeOfProperty<T, K extends keyof T> = T[K]; ``` 这里,`TypeOfProperty`是一个泛型类型,它接受两个类型参数:`T`(一个对象类型)和`K`(`T`的键的类型,且该键必须存在于`T`中)。`T[K]`表示访问`T`类型中键为`K`的属性的类型。 **示例**: ```typescript interface Person { name: string; age: number; isStudent: boolean; } type NameType = TypeOfProperty<Person, 'name'>; // string type AgeType = TypeOfProperty<Person, 'age'>; // number const name: NameType = 'Alice'; const age: AgeType = 30; ``` 在这个例子中,我们定义了一个`Person`接口,并通过`TypeOfProperty`泛型类型获取了`name`和`age`属性的类型。 #### 三、映射索引类型(Mapped Indexed Types) 映射索引类型是基于索引签名和条件类型构建的,它允许我们根据一个类型的所有键(或满足特定条件的键)来创建一个新的类型。这通常用于在编译时转换类型结构,如添加、修改或删除属性的类型。 **语法**: ```typescript type MappedType<T> = { [P in keyof T]: /* 转换逻辑 */; }; ``` 这里,`MappedType`是一个泛型类型,它遍历`T`的所有键(`keyof T`),并对每个键`P`应用一个转换逻辑来生成新的类型。 **示例**: ```typescript interface Person { name: string; age: number; isStudent: boolean; } type PartialPerson<T> = { [P in keyof T]?: T[P]; }; type PartialPersonType = PartialPerson<Person>; /* { name?: string | undefined; age?: number | undefined; isStudent?: boolean | undefined; } */ const partialPerson: PartialPersonType = { name: 'Bob', // age 和 isStudent 是可选的 }; ``` 在这个例子中,我们定义了一个`PartialPerson`泛型类型,它使用映射索引类型将`Person`接口的所有属性变为可选的。 #### 四、索引类型的高级应用 索引类型不仅限于上述基础用法,它还可以与其他高级类型特性结合,实现更为复杂的类型变换。 **1. 过滤键** 有时,我们可能只想从一个类型中选取满足特定条件的键。这可以通过结合条件类型来实现。 **示例**: ```typescript type FilterKeys<T, U> = { [P in keyof T]: T[P] extends U ? P : never; }[keyof T]; type StringKeys<T> = FilterKeys<T, string>; interface Example { a: number; b: string; c: boolean; d: string; } type StringOnlyKeys = StringKeys<Example>; // 'b' | 'd' ``` **2. 读取联合类型的所有键** 当处理联合类型时,我们可能想要获取所有可能键的集合。这同样可以通过索引类型和条件类型来实现。 **示例**: ```typescript type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; type KeysOfUnion<T> = keyof UnionToIntersection<T[keyof T]>; type MyUnion = { id: string; name: string } | { id: number; code: number }; type UnionKeys = KeysOfUnion<MyUnion>; // "id" | "name" | "code" ``` 这个例子中,`UnionToIntersection`和`KeysOfUnion`类型组合使用,将联合类型的所有成员合并为一个交叉类型,然后从中提取键的类型。 #### 五、总结 索引类型在TypeScript中是一个强大的工具,它允许我们基于对象的索引签名进行类型操作,实现类型的映射、过滤、转换等复杂逻辑。通过结合条件类型、映射索引类型等高级特性,我们可以构建出更加灵活、强大的类型系统,从而编写出更加安全、易于维护的TypeScript代码。在编写复杂应用或库时,深入理解并灵活运用索引类型,将极大地提升开发效率和代码质量。
上一篇:
18 | 高级类型(1):交叉类型与联合类型
下一篇:
20 | 高级类型(3):映射类型
该分类下的相关小册推荐:
TypeScript 全面进阶指南
TypeScript入门指南
剑指TypeScript