介绍
在写动态和可重复使用的代码时,遵循不要重复
原则(DRY)很重要。
使用通用代码,您可以编写动态和可重复使用的通用代码块;此外,您可以将通用代码应用于 TypeScript 中的类、接口和函数。
在本文中,您将将通用元素集成到您的TypeScript代码中,并将其应用到函数和类中,您还将学习如何使用界面在TypeScript中添加通用元素的限制。
前提条件
要成功完成本教程,您将需要以下内容:
- 最新版本的 TypeScript 已安装在您的计算机上. 此 如何设置新的 TypeScript 项目教程可以帮助您实现这一点.
- 最新版本的
ts-node
已安装. 如果您想测试和运行您的 TypeScript 代码,这项教程是必要的。
步骤1 - 了解通用药物
有时,您可能需要对不同数据类型重复相同的代码块. 以下是对两个不同的数据类型使用相同函数的示例:
1// for number type
2function fun(args: number): number {
3 return args;
4}
5
6// for string type
7function fun(args: string): string {
8 return args;
9}
请注意,在本示例中,对于数字
和字符串
类型重复相同的函数。
有一个名为任何
的类型,您可以使用它来实现代码中的通用药物的相同效果。使用任何
类型将允许您退出类型检查。
要在实践中看到这一点,请将任何
类型应用到前面的代码示例中:
1function fun(args: any): any {
2 return args;
3}
将数字
和字符串
类型替换为任何
类型,使函数成为通用函数,但使用任何
类型意味着乐趣
函数可以接受任何数据,因此,您也会失去类型安全性。
虽然使用任何
类型是使您的 TypeScript 代码更通用的一种方法,但它可能并不总是最好的选择。
步骤2 - 创建安全型通用药物
要创建类型安全的通用元素,您需要使用Type
参数。Type
参数被定义为T
或T>
。
返回乐趣
函数,使用T
使您的通用函数安全:
1[label index.ts]
2function fun<T>(args:T):T {
3 return args;
4}
因此,fun
现在是一个类型安全的通用函数. 要测试这种类型安全的通用函数,请创建一个名为result
的变量,并用一个string
类型的参数将其设置为fun
。
1[label index.ts]
2let result = fun<string>("Hello World");
尝试使用乐趣
函数与数字
类型. 将参数设置为200
:
1[label index.ts]
2let result2 = fun<number>(200);
如果您想看到此代码的结果,您可以添加console.log
语句,将result
和result2
打印到控制台:
1[label index.ts]
2console.log(result);
3console.log(result2);
最后,你的代码应该是这样的:
1[label index.ts]
2function fun<T>(args:T):T {
3 return args;
4}
5
6let result = fun<string>("Hello World");
7let result2 = fun<number>(200);
8
9console.log(result);
10console.log(result2);
使用ts-node
在控制台中运行此 TypeScript 代码:
1npx ts-node index.ts
代码不会出现错误,你会看到这个输出:
1[secondary_label Output]
2Hello World
3200
现在您可以为具有单个参数的函数创建安全型号的通用元素,并且了解如何为具有多个参数的多种函数创建通用元素也很重要。
步骤 3 – 使用具有许多类型的参数的通用药物
如果函数中有许多参数,您可以使用不同的字母来表示类型,您不需要只使用T
:
1[label params.ts]
2function fun<T, U, V>(args1:T, args2: U, args3: V): V {
3 return args3;
4}
此函数采用3个参数,即args1
,args2
和arg3
,并返回args3
。这些参数不限于特定类型,因为T
,U
和V
被用作fun
函数参数的通用类型。
创建一个名为result3
的变量,并将其分配到fun
中。 包括< string, number, boolean>
类型来填写T
,U
和V
通用类型。
1[label params.ts]
2let result3 = fun<string, number, boolean>('hey', 3, false);
这将返回第三个参数,即false
。 若要查看此,您可以使用console.log
语句:
1[label params.ts]
2console.log(result3);
运行ts-node
命令以查看您的console.log
声明输出:
1npx ts-node params.ts
这将是产量:
1[secondary_label Output]
2false
现在您可以为具有多个参数的函数创建通用类型,就像函数一样,通用类型也可以与类
和接口
一起使用。
步骤 4 – 创建通用类
类可以是通用函数,类也可以是通用函数。在角度(<>
)中使用类
参数,就像在函数中一样。
创建一个使用数字
和字符串
输入的类,并使用这些输入创建一个数组。
1[label classes.ts]
2class customArray<T> {
3 private arr: T[] = [];
4}
现在,你的数组包含不同类型的项目已经到位. 创建一个名为getItems
的方法,返回customArray
数组:
1[label classes.ts]
2getItems (arr: T[]) {
3 return this.arr = arr;
4}
创建名为addItem
的方法,将新项目添加到customArray
数组的末尾:
1[label classes.ts]
2addItem(item:T) {
3 this.arr.push(item);
4}
arr:T[]
参数意味着数组中的项目可以是任何类型的,因此customArray
可以是数组,布尔符号或字符串。
添加一种名为removeItem
的方法,从customArray
中删除指定的项目:
1[label classes.ts]
2removeItem(item: T) {
3 let index = this.arr.indexOf(item);
4 if(index > -1)
5 this.arr.splice(index, 1);
6}
与addItem
方法一样,removeItem
采取任何类型的参数,并从customArray
数组中删除指定的参数。
现在,通用类customArray
已完成,为数字
和字符串
类型创建一个customArray
实例。
声明名为numObj
的变量为number
类型的customArray
实例:
1[label classes.ts]
2let numObj = new customArray<number>();
使用addItem
方法将数字10
添加到numObj
:
1[label classes.ts]
2numObj.addItem(10);
由于customArray
是通用的,所以它也可以用来创建一个字符串的数组。创建一个名为strObj
的变量,为字符串类型创建一个等于customArray
的实例:
1[label classes.ts]
2let strObj = new customArray<string>();
使用addItem
方法将字符串Robin
添加到strObj
数组中。
1[label classes.ts]
2strObj.addItem(“Robin”);
若要查看代码的结果,请为numObj
和strObj
创建一个console.log
声明:
1[label classes.ts]
2console.log(numObj);
3console.log(strObj);
最后,你的代码应该是这样的:
1[label classes.ts]
2class customArray<T> {
3 private arr: T[] = [];
4
5 getItems(arr: T[]) {
6 return this.arr = arr;
7 }
8
9 addItem(item:T) {
10 this.arr.push(item);
11 }
12
13 removeItem(item: T) {
14 let index = this.arr.indexOf(item);
15 if(index > -1)
16 this.arr.splice(index, 1);
17 }
18}
19
20let numObj = new customArray<number>();
21numObj.addItem(10);
22
23let strObj = new customArray<string>();
24strObj.addItem(“Robin”);
25
26console.log(numObj);
27console.log(strObj);
运行ts-node
后,这就是你将收到的输出:
1[secondary_label Output]
2customArray { arr: [ 10 ] }
3customArray { arr: [ 'Robin' ] }
您使用了customArray
类用于数字
和字符串
类型,您可以通过使用通用类型来实现这一目标,但是,使用通用药物确实存在一些限制。
步骤5 – 了解通用限制
到目前为止,您已经使用通用元素创建了函数和类,但使用通用元素有一个缺点. 要在操作中看到此缺点,请写一个名为getLength
的函数,该函数的参数返回长度
:
1[label constraints.ts]
2function getLength<T>(args: T) : number {
3 return args.length;
4}
只要通过类型具有长度
属性,此函数将工作,但没有长度
属性的数据类型将产生例外。
要做到这一点,您首先需要创建一个名为funcArgs
的界面,并定义一个长度
属性:
1[label constraints.ts]
2interface funcArgs {
3 length: number;
4}
现在,更改getLength
函数并扩展
它以包括funcArgs
界面作为限制:
1[label constraints.ts]
2function getLength<T extends funcArgs>(args:T) : number {
3 return args.length;
4}
您已使用接口创建了一种通用限制。 此外,您还与此接口扩展了getLength
函数。 它现在需要长度
作为所需参数。
要在行动中看到这一点,请声明一个名为result4
的变量,并将其分配到getLength
中,其参数为3
:
1[label constraints.ts]
2let result4 = getLength(3);
这会返回错误,因为不包含长度
参数的值:
1[secondary_label Output]
2⨯ Unable to compile TypeScript:
3index.ts:53:25 - error TS2345: Argument of type 'number' is not assignable to parameter of type 'funcArgs'.
4
553 let result4 = getLength(3);
要调用getLength
函数,您需要包含一个长度
参数以及一个名称
参数:
1[label constraints.ts]
2let result = getLength({ length: 5, name: 'Hello'});
此通话具有长度
属性,您的函数将正常工作,不会显示任何错误消息。
结论
在本教程中,您成功地将通用元素整合到您的TypeScript函数和类中,您还包括了对通用元素的限制。
如果您想了解如何在 VS Code 中使用 TypeScript,则本文 如何在 Visual Studio Code 中使用 TypeScript是开始的好地方。