# typescript(五) - 泛型

# 泛型的定义

泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性

在我们阅读框架源码的时候, 发现使用的最多的就是泛型了

# 泛型初体验

假设我们写一个创造数组的函数




 





function createArray(length: number, value: any): Array<any> {
    let res: any = []
    for (let i = 0; i < length; i++) {
        res[i] = value
    }
    return res
}
console.log(createArray(6, 9)) // [ 9, 9, 9, 9, 9, 9 ]

我们会发现要实现这个函数, 离不开any, 而且这样的话相当于是写死了返回函数的类型, 如只返回了字符串数组或者只返回数字数组, 我们来看下使用泛型之后实现的这个方法




 







function createArray<T>(length: number, value: T): Array<T> {
    let res: T[] = []
    for (let i = 0; i < length; i++) {
        res[i] = value
    }
    return res
}
console.log(createArray<number>(6, 9)) // [ 9, 9, 9, 9, 9, 9 ]
console.log(createArray<string>(6, 9)) //类型“9”的参数不能赋给类型“string”的参数
console.log(createArray<string>(6, '9')) // [ '9', '9', '9', '9', '9', '9' ]

我们可以大致理解一下泛型的作用, 泛型可以申明一个很随意的类型, 这个类型是调用的时候传入的类型

# 类中使用泛型

我们知道泛型的大概作用之后, 我们试下在类中使用泛型




 









class People<T> {
    constructor(public name:T){}
    getName():T{
        return this.name
    }
}
let p = new People<string>('chenying')
console.log(p.getName())
let p1 = new People<number>('chenying') // err 类型“"chenying"”的参数不能赋给类型“number”的参数。
console.log(p1.getName())

当我们new People的时候泛型写string, 那么传入的name只可以为string, 否则报错

# 定义接口时候使用泛型




 



interface ObjInterface<T> {
    name: T
}
let obj:ObjInterface<string> = {
    name: 'chenying',// 如果是其他类型会报错
}

# 泛型约束

在函数中使用泛型的时候,由于预先并不知道泛型的类型,所以不能随意访问相应类型的属性或方法。




 
function logger<T>(val: T) {
    console.log(val.length); // err
}

我们发现上述代码会报错, 因为泛型的类型不能确定然后我们就直接调用了字符串的方法,这种情况我们可以通过泛型继承接口来实现




 







function logger<T>(val: T) {
    console.log(val.length); 
}
interface LengthWise {
    length: number
}
//可以让泛型继承一个接口
function logger2<T extends LengthWise>(val: T) {
    console.log(val.length)
}

因为泛型继承的接口中有lenght属性, 所以是不会报错的

# 默认泛型类型

有时候我们使用泛型的时候不定义泛型的类型, 但是我们希望没有给泛型定义类型的时候有一个默认的类型, 可以这么写




 

function logger<T = number>(a: T): T {
    return a 
}
logger(1) // 默认是number

# 多个类型参数

引入网上一道面试题, 如果在不使用第三方变量的情况下调换两个变量的位置




 




function swap<A,B>(tuple:[A,B]):[B,A]{
  return [tuple[1],tuple[0]];
}
let swapped = swap<string,number>(['a',1]);
console.log(swapped);
console.log(swapped[0].toFixed(2));
console.log(swapped[1].length);

其实本质上是[a, b] = [b, a]