是什么
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
定义的是类型,不是值。扩展函数,接口,类的功能。
优势&为什么使用泛型
- 函数和类支持多种类型,增强程序扩展性。
- 不必写多余的函数重载和冗长的联合类型声明,增强代码可读性。
- 灵活控制类型之间的约束.
对于泛型的实践来说,使用是需要一定理解,复杂的泛型使用会非常的复杂。
经典例子
问题:定义了一个通用函数log,要求返回值的类型与传入参数的类型是相同的。
方案一: 给输入参数value设置any类型,函数返回值类型也为any。
缺点: any会丢失信息,像第一个例子那像保持准确性,传入数值类型并返回数值类型。
function log(value: any): any {
console.log(value)
return value;
}
方案二:泛型
(1) 定义泛型
function log<T>(value: T): T { // 函数后面加入<T>,给输入参数value设置T类型,函数返回值类型也为T。
console.log(value)
return value;
}
log('d')
(2) 调用泛型
(a)调用时直接制定T的类型,将带有的地方,换成参数类型。\
log<string[]>(['a', 'b', 'c'])
(b) 省略类型参数,利用类型推断。---推荐方式\
log(['a', 'b', 'c'])
泛型函数
function setSex<T> (sex: T) {}
setSex<'男'>('女')
泛型接口
在定义接口时,为接口的属性或者方法定义泛型类型。在使用接口时,再指定具体的泛型类型
interface Log<T> {
value: T
}
let myLog: Log<string> = {
value: 'aa'
}
type Generics<T> = {
name: string
age: number
sex: T
}
interface Generics<T> {
name: string
age: number
sex: T
}
泛型类
class Log<T> {
run (value: T) {
console.log(value)
return value;
}
}
let log1 = new Log<number>();
log1.run(2)
let log2 = new Log(); // 没写类型的,log2可多中类型。
log2.run({});
log2.run('dd')
泛型约束: 对泛型进行一定的约束。
T必须满足extends的约束。
function log<T>(value: T): T {
console.log(value, value.length)
return value;
}
定义一个log函数,打印值和值的length属性。但是value不一定有length属性。解决
interface Length {
length: number
}
function log<T extends Length>(value: T): T {
console.log(value, value.length)
return value;
}
log<string[]>(['a', 'b', 'c']) // 数组有length属性,可以
log(['a', 'b', 'c'])
log(1) // 报错 因为1 number没有length属性
定义一个接口,里面有length属性,让T继承这个接口Length。
对T进行了约束,不再是随便了的,输入的类型必须具有length属性。
泛型参数的默认类型
在 TypeScript 2.3 以后,我们可以为泛型中的类型参数指定默认类型。
当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推测出时,这个默认类型就会起作用。
泛型参数默认类型与普通函数默认值类似,对应的语法很简单,即 <T=Default Type> ,对应的使⽤示
例如下:
interface A<T = string> {
name: T;
}
const strA: A = {
name: "Semlinker"
};
const numB: A<number> = {
name: 101
};