一、概念
不预先确定的数据类型,具体的类型在使用的时候才能确定。
泛型约定,函数的输入类型和输出类型必须一样。
function log<T>(value: T): T {
console.log(value)
return value;
}
// 调用该函数的时候,传入的是什么类型,输出的也是什么类型
console.log(log([1, 2])) // [1, 2]
console.log(log(1,2)) // 1, 2
log<string[]>(['a', 'b'])
二、泛型函数
function log<T>(value: T): T {
return value;
}
console.log(log([1, 2]))
// 泛型函数
type Log = <T>(value: T) => T;
let myLog: Log = log;
三、泛型接口
// 泛型接口
// 第一种写法:
// interface Log {
// <T>(value: T): T;
// }
// 第二种写法
// 这样接口的所有成员都受到泛型约束
// 实现的时候,必须只能类型
// interface Log<T> {
// (value: T): T;
// }
// let myLog: Log<number> = log
// myLog(1)
// 这时myLog的参数只能是number
// 第三种写法,在接口泛型上添加默认类型
interface Log<T = string> {
(value: T): T;
}
let myLog: Log = log
myLog('aaa')
四、泛型类
// 泛型也可以约束类的成员。
// 泛型不能应用类的静态成员
// 泛型类
class Log<T> {
run (value: T) {
return value
}
}
let log1 = new Log<number>()
log1.run(1)
let log2 = new Log()
log2.run('1')
五、泛型约束
// 泛型约束
interface Length {
length: number
}
function log<T extends Length>(value: T) {
return value
}
// 这样不管参数是什么,都要有length属性
// log(1) // 不行
log([1]) // 可以
六、泛型的好处
- 函数和类可以轻松的支持多种类型,增强程序的扩展性
- 不必写多条函数重载,冗长的联合类型声明,增强代码的可读性
- 灵活控制类型之间的约束