泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
泛型T
作用域只限于函数内部使用
- 泛型函数
- 首先,我们来实现一个函数 createArray,它可以创建一个指定长度的数组,同时将每一项都填充一个默认值
function createArray(length: number, value: any): Array<any> {
let result: any = [];
for(let i=0;i<length;i++){
result[i] = value;
}
return result;
}
let result = createArray(3,'x');
console.log(result);
使用泛型后
function createArray<T>(length: number, value: T): Array<T> { //这样,就约束了返回数组的类型
let result: T[] = [];
for(let i=0;i<length;i++){
result[i] = value;
}
return result;
}
let arr = createArray<number>(3, 5);
let arr = createArray<number>(3, "a");
- 泛型类
- 类数组(Array-like Object)不是数组类型,比如 arguments
class Person<T> { // T的作用域是整个类
private list: T[] = [];
add(value: T) {
this.list.push(value);
}
getMax() {
let result: T = this.list[0];
for(let i =1;i<this.list.length;i++){
if(this.list[i] > result){
result = this.list[i];
}
}
return result;
}
}
3.泛型接口
- 泛型接口可以用来约束函数
interface Caculate {
<T>(a: T, b: T): T
}
const add: Caculate = function <T>(a: T, b: T): T{
return a
}
add<number>(3,5)
add<number>(3,"5") //报错,此处T是number,“5”是字符串
- 多个类型参数
function swap<A, B>(touple: [A, B]): [B, A] { //touple是元组
return [touple[1], touple[0]]
}
let swapped = swap<string,number>(['a',1]);
console.log(swapped);
console.log(swapped[0].toFixed(2));
console.log(swapped[1].length);
- 默认泛型类型
function createArray3<T=number>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
let result2 = createArray3(3,3);
let result3 = createArray3<string>(3,'3');
- 泛型约束
- 在函数中使用泛型的时候,由于预先并不知道泛型的类型,所以不能随意访问相应类型的属性或方法。
function logger<T>(val: T) {
console.log(val.length); //直接访问会报错,因为T类型未知,不一定有length属性
}
interface LengthWise {
length: number
}
//可以让泛型继承一个接口
function logger2<T extends LengthWise>(val: T) {
console.log(val.length)
}
logger2('lc'); // 2
logger2({length: 5}); //5
logger2(1); //报错,1或者new Number(1)都没有length属性
- 泛型接口
- 定义接口的时候也可以指定泛型
interface Cart<T>{
list:T[]
}
let cart:Cart<{name:string,price:number}> = {
list:[{name:'zhufeng',price:10}]
}
console.log(cart.list[0].name,cart.list[0].price);
- 泛型类型别名
- 泛型类型别名可以表达更复杂的类型
type Cart<T> = {list:T[]} | T[]; //联合类型
let c1:Cart<string> = {list:['1']};
let c2:Cart<number> = [1];
- 泛型接口 vs 泛型类型别名
- 接口创建了一个新的名字,它可以在其他任意地方被调用。而类型别名并不创建新的名字,例如报错信息就不会使用别名
- 类型别名不能被 extends和 implements,这时我们应该尽量使用接口代替类型别名
- 当我们需要使用联合类型或者元组类型的时候,类型别名会更合适
网友评论