5.泛型
## 泛型的定义
**泛型**:在软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑泛用性,组件不仅能够支持当前的数据类型,同时也能支持未来的的类型。这在创建大型系统时为你提供了十分灵活的功能。
在像C#和Java这样的语言,可以用泛型创建重要的组件,一个组件可以支持多种类型的数据。这样用户可以以自己的数据类型来使用组件。
通俗理解,泛型是解决 类、接口、方法的复用性、以及对不特定数据类型的支持。
泛型可以帮我们避免重复的代码以及对不特定数据类型的支持(数据校验),
## 泛型的函数
```
function identity<T>(arg: T): T {//要求传入参数和返回参数类型一致。
return arg;
}
```
`T`表示泛型,具体是什么类型由调用方法决定。
## 泛型接口
```
interface GenericIdentityFn {
<T>(arg: T): T;
}
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: GenericIdentityFn = identity;
```
一个相似的例子,我们可能想把泛型参数当作整个接口的一个参数。 这样我们就能清楚的知道使用的++具体是哪个泛型类型++(比如: Dictionary<string>而不只是Dictionary)。 这样接口里的其它成员也能知道这个参数的类型了。
```
interface GenericIdentityFn<T> {
(arg: T): T;
}
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: GenericIdentityFn<number> = identity;
```
注意,我们的示例做了少许改动。 不再描述泛型函数,而是把非泛型函数签名作为泛型类型一部分。 当我们使用 GenericIdentityFn的时候,还得传入一个类型参数来指定泛型类型(这里是:number),锁定了之后代码里使用的类型。 对于描述哪部分类型属于泛型部分来说,理解何时把参数放在调用签名里和何时放在接口上是很有帮助的。
## 泛型类
```
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
```
```
let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = function(x, y) { return x + y; };
console.log(stringNumeric.add(stringNumeric.zeroValue, "test"));
```
## 补充
- <T> or <other> 约束参数