Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

typescript(五) - 泛型 #27

Open
YIngChenIt opened this issue Jun 30, 2020 · 0 comments
Open

typescript(五) - 泛型 #27

YIngChenIt opened this issue Jun 30, 2020 · 0 comments

Comments

@YIngChenIt
Copy link
Owner

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]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant