在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定具体类型。
函数泛型
需求:定义一个函数,接收两个参数,第一个是数据,第二个是数量,生成一个数据*数量的数组
(() => {
// 根据传入的数据和数量,生成一个数据*数量的数组
function getArr(value:any,count:number):any[]{
const arr:any[]=[]
for (let i=0;i<count;i++){
arr.push(value)
}
return arr
}
console.log(getArr(1,3))
console.log(getArr('1',3))
})()
// 输出结果
// (3) [1, 1, 1]
// (3) ["1", "1", "1"]
多个泛型参数的函数
一个函数中可以有多个泛型参数
(() => {
// 使用k和v表示不同的值类型,所有引用了K的变量类型一致,V也是
function swap<K, V>(a: K, b: V): [K, V] {
return [a, b]
}
// 调用的时候指定参数的类型
const result = swap<string, number>('abc', 123)
// ts编译器识别出变量的类型,并提供相关的方法提示
console.log(result[0].length, result[1].toFixed())
})()
// 输出结果
// 3 "123"
泛型接口
在定义接口时, 为接口中的属性或方法定义泛型类型 在使用接口时, 再指定具体的泛型类型
(() => {
// 在定义接口时, 为接口中的属性或方法定义泛型类型
interface IbaseCRUD <T> {
data: T[]
add: (t: T) => void
}
// 在使用接口时, 再指定具体的泛型类型
// 定义一个类,并指定成员属性的值类型
class User {
id?: number; //id主键自增
name: string; //姓名
age: number; //年龄
// 构造方法,更新属性数据
constructor (name, age) {
this.name = name
this.age = age
}
}
// 定义一个类,这个类的类型就是上面定义的接口,传入上面定义的类
class UserCRUD implements IbaseCRUD <User> {
data: User[] = []
add(user: User): void {
user = {...user, id: Date.now()}
this.data.push(user)
console.log('保存user', user.id)
}
}
// 实例化对象
const userCRUD = new UserCRUD()
// 调用add方法添加用户到user列表
userCRUD.add(new User('tom', 12))
userCRUD.add(new User('tom2', 13))
console.log(userCRUD.data)
})()
// 输出结果
// 保存user 1614172477494
// 保存user 1614172477495
//
// (2) [{…}, {…}]
// 0: {name: "tom", age: 12, id: 1614172477494}
// 1: {name: "tom2", age: 13, id: 1614172477495}
// length: 2
泛型类
在定义类时, 为类中的属性或方法定义泛型类型 在创建类的实例时, 再指定特定的泛型类型
(() => {
// 定义一个类, 类中的属性和方法定义泛型类型(T表示同种类型)
class GenericNumber<T> {
zeroValue: T
add: (x: T, y: T) => T
}
// 实例化对象,指定类型为number
let myGenericNumber = new GenericNumber<number>()
myGenericNumber.zeroValue = 0
myGenericNumber.add = function (x, y) {
return x + y
}
// 调用对象的方法,传入number参数
console.log(myGenericNumber.add(myGenericNumber.zeroValue, 12))
// 实例化对象,指定类型为string
let myGenericString = new GenericNumber<string>()
myGenericString.zeroValue = 'abc'
myGenericString.add = function (x, y) {
return x + y
}
// 调用对象的方法,传传入string参数
console.log(myGenericString.add(myGenericString.zeroValue, '-def'))
})()
// 输出结果
// 12
// abc-def
泛型约束
没有泛型约束
(() => {
function fn <T>(x: T): void {
// 对一个泛型参数取 length 属性, 会报错, 因为这个泛型根本就不知道它有这个属性
console.log(x.length)
}
})()
// 输出结果
error TS2339: Property 'length' does not exist on type 'T'.
使用泛型约束
(() => {
// 定义一个泛型约束
interface Lengthwise {
length: number;
}
// 指定泛型约束
function fn2<T extends Lengthwise>(x: T): void {
console.log(x.length)
}
fn2('abc')
// 当传入值不符合约束类型时,会报错:
fn2(123) // error number没有length属性
})()
// 输出结果
// 3
// error TS2345: Argument of type 'number' is not assignable to parameter of type 'Lengthwise'.