TypeScript(7)泛型

泛型

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

创新互联服务项目包括广州网站建设、广州网站制作、广州网页制作以及广州网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,广州网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到广州省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!

引入

下面创建一个函数, 实现功能: 根据指定的数量 count 和数据 value , 创建一个包含 countvalue 的数组 不用泛型的话,这个函数可能是下面这样:

function createArray(value: any, count: number): any[] {
    const arr: any[] = []
    for (let index=0; index < count; index++) {
        arr.push(value)
    }
    return arr
}

const arr1 = createArray('a', 3)
const arr2 = createArray(1, 3)
console.log(arr1)
console.log(arr2)
console.log(arr1[0].toFixed(), arr2[0].split(''))

我们创建了一个函数createArray,传入2个参数valuecount,返回any类型的数组,然后定义了一个any类型的空数组arr。接下来我们查看结果

在编译阶段我们没有报错是因为,我们把value设置为了any类型,但是当编译完成后运行时,arr1是字符串,字符串是没有toFixed方法的,所以会报错,那么我们希望在编译阶段就报错,就可以使用泛型

使用泛型

// 使用函数泛型
function createArray(value: T, count: number): T[] {
    const arr: Array = []
    for (let index=0; index < count; index++) {
        arr.push(value)
    }
    return arr
}
const arr1 = createArray(11, 3)
console.log(arr1[0].toFixed())
const arr2 = createArray('AA', 3)
console.log(arr2[0].split(''))
console.log('---------')
console.log(arr2[0].toFixed())  // 报错,因为字符串没有toFixed方法
console.log(arr1[0].split(''))  // 报错,因为number没有split方法

泛型的意思就是类型由用户自己决定,比如function createArray(value: T, count: number): T[],函数createArrayvalue参数和返回类型都由用户自己决定。
const arr1 = createArray(11, 3)这句代码是没问题,因为规定了number类型,传入的也是number

当我们将代码修改成如下代码:

我们发现报错了,因为规定了number类型,传入的却是字符串11

当我们输入如下代码,也会报错

报错原因如下

所以如果我们使用了泛型,就会避免类型输入错误或者用错方法

多个泛型参数的函数

一个函数可以定义多个泛型参数

function swap  (a: K, b: V): [K, V] {
  return [a, b]
}
const result = swap('abc', 123)
console.log(result[0].length, result[1].toFixed())

泛型接口

interface IbaseCRUD  {
    // 定义泛型数组data
    data: T[]
    add: (t: T) => void
    getById: (id: number) => T
}

class User {
    id?: number;
    name: string;
    age: number;

    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
}

class UserCRUD implements IbaseCRUD {
    data: User[] = []

    add(user: User): void {
        user = {...user, id: Date.now()}
        this.data.push(user)
        console.log('保存user', user.id)
    }

    getById(id: number): User {
        return this.data.find(item => item.id === id)
    }
}


const userCRUD = new UserCRUD()
userCRUD.add(new User('tom', 12))
userCRUD.add(new User('tom2', 13))
console.log(userCRUD.data)

泛型类

泛型类看上去与泛型接口差不多。 泛型类使用( <>)括起泛型类型,跟在类名后面。

class GenericNumber {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };

GenericNumber类的使用是十分直观的,并且你可能已经注意到了,没有什么去限制它只能使用number类型。 也可以使用字符串或其它更复杂的类型。

let stringNumeric = new GenericNumber();
stringNumeric.zeroValue = "";
stringNumeric.add = function(x, y) { return x + y; };

console.log(stringNumeric.add(stringNumeric.zeroValue, "test"));

与接口一样,直接把泛型类型放在类后面,可以帮助我们确认类的所有属性都在使用相同的类型。

泛型约束

如果我们直接对一个泛型参数取 length 属性, 会报错, 因为这个泛型根本就不知道它有这个属性

// 没有泛型约束
function fn (x: T): void {
  console.log(x.length)  // 报错,因为目前不知道x是什么类型
}

我们可以使用泛型约束来实现

interface Lengthwise {
  length: number;
}

// 指定泛型约束
function fn2 (x: T): void {
  console.log(x.length)
}

我们需要传入符合约束类型的值,必须包含必须 length 属性:

fn2('abc')
// fn2(123) // error  number没有length属性

分享名称:TypeScript(7)泛型
转载来源:http://scyanting.com/article/dsojpde.html