1.泛型定义
- 泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
- 泛型
T
作用域只限于函数内部使用
2.泛型函数
创建一个identity函数。这个函数会返回任何传入它的值。 你可以把这个函数当成是echo
命令。
function identity(arg: number): number {
return arg;
}
/**
* 使用any类型来定义函数
* 使用any类型后这个函数已经能接收任何类型的arg参数,
但是却丢失了一些信息
* 传入的类型与返回的类型应该是相同的。
* 如果我们传入一个数字,我们只知道任何类型的值都有可能被返回。
*/
function identity(arg: any): any {
return arg;
}
我们需要一种方法使返回值的类型与传入参数的类型是相同的。 这里,我们使用了 _类型变量_,它是一种特殊的变量,只用于表示类型而不是值。
/**
* 给identity添加了类型变量T。
* T帮助我们捕获用户传入的类型(比如:number),之后我们就可以使用这个类型。
* 之后我们再次使用了 T当做返回值类型。
* 这允许我们跟踪函数里使用的类型的信息。
* 我们把这个版本的identity函数叫做泛型,因为它可以适用于多个类型。
* 不同于使用 any,它不会丢失信息.
*/
function identity<T>(arg:T):T{
return arg;
}
我们定义了泛型函数后,可以用两种方法使用。
//第一种,传入所有的参数,包含类型参数
let output1 = identity<string>("myString");
//第二种方法更普遍。利用了类型推论 -- 即编译器会根据传入的参数自动地帮助我们确定T的类型
let output2 = identity("myString");
3.泛型类
class MyArray<T> {
private list: T[] = [];
add(value: T) {
this.list.push(value);
}
getMax(): T {
let result = this.list[0];
for (let i = 0; i < this.list.length; i++) {
if (this.list[i] > result) {
result = this.list[i];
}
}
return result;
}
}
let arr = new MyArray();
arr.add(1);
arr.add(2);
arr.add(3);
let ret = arr.getMax();
console.log(ret);
4.泛型接口
泛型接口可以用来约束函数
interface Calculate{
<T>(a:T, b:T):T
}
let add:Calculate = function<T>(a:T, b:T){
return a;
}
console.log(add(1,2));//1
5.多个类型参数
泛型可以有多个
function swap<A, B>(tuple: [A, B]): [B, A] {
return [tuple[1], tuple[0]];
}
let swapped = swap(['a', 1]);
console.log(swapped);//[ 1, 'a' ]
6.默认泛型类型
function createArray<T=number>(length:number, value:T):Array<T>{
let result:T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
let result = createArray(3, 'fung');
console.log(result);//[ 'fung', 'fung', 'fung' ]
7.泛型约束
function logger<T> (val:T){
// console.log(val.length); //Erro
}
interface LengthWise{
length:number
}
function logger2<T extends LengthWise>(val: T){
console.log(val.length);
}
logger2('fung');//4
logger2(1);//类型“1”的参数不能赋给类型“LengthWise”的参数
8.泛型接口
interface Cart<T> {
list: T[];
}
let cart: Cart<{ name: string; price: number }> = {
list: [{ name: "fung", price: 10 }]
};
console.log(cart.list[0].name, cart.list[0].price); //fung 10
9.泛型类型别名
泛型类型别名可以表达更复杂的类型
type Cart<T> = { list: T[] } | T[];
let c1: Cart<string> = { list: ["1"] };
let c2: Cart<number> = [1];
10.泛型接口 VS 泛型类
- 接口创建了一个新的名字,它可以在其他任意地方被调用。
而类型别名并不创建新的名字,例如报错信息就不会使用别名
- 类型别名不能被 extends和 implements,这时我们应该尽量使用接口代替类型别名
- 当我们需要使用联合类型或者元组类型的时候,类型别名会更合适
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。