首页
技术小册
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开发实战
### 13 | 泛型(1):泛型函数与泛型接口 在TypeScript的世界中,泛型(Generics)是一种强大的特性,它允许我们在不损失灵活性的前提下,编写可复用的组件。泛型可以应用于函数、接口、类等多种结构,极大地提升了代码的可读性、可维护性和复用性。本章将深入探讨泛型的基础用法,特别是泛型函数与泛型接口,帮助读者理解并掌握这一核心概念。 #### 13.1 泛型概述 在TypeScript中,泛型允许我们定义一个组件(如函数、接口或类),这些组件可以工作于多种类型的数据之上,而无需在每次使用时都明确指定数据类型。这类似于在C#或Java中的模板(Templates)或泛型编程。使用泛型,我们可以编写更加灵活和可复用的代码,同时保留类型安全和编译时检查的好处。 #### 13.2 泛型函数 泛型函数是泛型在函数层面的应用。它允许我们在函数定义时,不指定具体的参数类型或返回类型,而是使用类型参数(Type Parameters)来代表这些类型,这些类型参数会在函数被调用时确定。 ##### 13.2.1 基本语法 泛型函数的定义通过在函数名后面添加尖括号(`<>`)来指定类型参数,类型参数可以是一个或多个,用逗号分隔。 ```typescript function identity<T>(arg: T): T { return arg; } let output = identity<string>("myString"); // 明确指定类型参数 let outputNum = identity(42); // TypeScript会自动推断类型参数为number ``` 在上面的例子中,`identity`是一个泛型函数,它接受一个类型为`T`的参数`arg`,并返回相同类型的值。在调用`identity`时,我们可以显式地指定`T`的类型(如`identity<string>("myString")`),但TypeScript的类型推断机制通常能够自动完成这一任务(如`identity(42)`)。 ##### 13.2.2 泛型约束 有时,我们希望对泛型进行一定的约束,以确保其至少具有某些属性或方法。这可以通过泛型约束来实现。 ```typescript interface Lengthwise { length: number; } function loggingIdentity<T extends Lengthwise>(arg: T): T { console.log(arg.length); // 现在我们知道arg具有length属性 return arg; } // 使用时,TypeScript会检查传入的参数是否实现了Lengthwise接口 loggingIdentity({ length: 10, value: "hello world" }); loggingIdentity([1, 2, 3]); // 数组也实现了Lengthwise接口 ``` 在这个例子中,我们定义了一个`Lengthwise`接口,它要求实现该接口的对象必须有一个`length`属性。然后,我们修改了`loggingIdentity`函数,使其仅接受实现了`Lengthwise`接口的对象作为参数。这确保了`arg.length`是有效的访问。 #### 13.3 泛型接口 泛型接口是泛型在接口层面的应用。与泛型函数类似,泛型接口允许我们在定义接口时不指定具体的类型,而是在实现接口时由具体的类来指定。 ##### 13.3.1 泛型接口定义 泛型接口通过在接口名后添加尖括号(`<>`)并定义类型参数来定义。 ```typescript interface GenericIdentityFn<T> { (arg: T): T; } function identityFn<T>(arg: T): T { return arg; } let myIdentity: GenericIdentityFn<number> = identityFn; ``` 在这个例子中,我们定义了一个名为`GenericIdentityFn`的泛型接口,它描述了一个接受一个类型为`T`的参数并返回相同类型值的函数。然后,我们定义了一个普通的泛型函数`identityFn`,并证明它符合`GenericIdentityFn<number>`接口的类型。 ##### 13.3.2 泛型接口与类 泛型接口也可以被类实现,这为类的设计带来了极大的灵活性。 ```typescript interface GenericNumber<T> { zeroValue: T; add: (x: T, y: T) => T; } class Numeric<T> implements GenericNumber<T> { zeroValue: T; add: (x: T, y: T) => T; constructor(zeroValue: T, add: (x: T, y: T) => T) { this.zeroValue = zeroValue; this.add = add; } } let myGenerics = new Numeric<number>(0, (x, y) => x + y); console.log(myGenerics.add(1, 2)); // 输出: 3 ``` 在这个例子中,我们定义了一个`GenericNumber`接口,它要求实现该接口的类必须有一个`zeroValue`属性和一个`add`方法。然后,我们定义了一个`Numeric`类,它接受两个泛型参数(尽管在这个例子中我们只使用了`T`),并实现了`GenericNumber`接口。通过这种方式,`Numeric`类可以处理任何类型的数据,只要这些数据支持加法运算和有一个“零”值的概念。 #### 13.4 总结 泛型是TypeScript中一个非常重要的特性,它允许我们编写更加灵活、可复用和类型安全的代码。通过泛型函数和泛型接口,我们可以在不牺牲类型安全的前提下,编写能够处理多种类型数据的函数和接口。泛型约束则进一步增强了泛型的表达能力,允许我们对泛型进行限制,以确保它们满足特定的条件。 在本章中,我们深入探讨了泛型函数和泛型接口的基本概念、语法以及实际应用。通过示例代码,我们展示了如何定义泛型函数和接口,以及如何在函数和类中实现和使用它们。掌握这些基础知识后,读者将能够更加有效地利用TypeScript的泛型特性,编写出更加高效、健壮和易于维护的代码。
上一篇:
12 | 类与接口的关系
下一篇:
14 | 泛型(2):泛型类与泛型约束
该分类下的相关小册推荐:
剑指TypeScript
TypeScript 全面进阶指南
TypeScript入门指南