泛型的概念
很多时候我们希望一个函数或者一个类支持多种数据类型,有很大灵活性。
下面举个例子:一个打印函数
function log(value: string): string {
console.log(value);
return value;
}
希望这个函数支持字符串数组,应该如何实现?
- 通过函数重载
function log(value: string): string;
function log(value: string[]): string[];
function log(value: any) {
console.log(value);
return value;
}
- 联合类型
function log(value: string | string[]): string | string[] {
console.log(value);
return value;
}
- any 类型
function log(value: any): any {
console.log(value);
return value;
}
any 类型丢失了一些信息,也就是类型之间的约束关系,它忽略了输入类型跟返回类型必须是一致的,我们无法获知这种约束福安息,这个时候就需要用到泛型。
泛型:不预先确定的类型,具体的类型在使用的时候才能确定。
泛型的使用
使用泛型改造上面的打印函数
- 类型 T 不需要预先的指定,就相当于 any 类型
- 保证了输入参数跟返回值的类型是一致的
function log<T>(value: T): T {
console.log(value);
return value;
}
调用方式
// 直接指明 T 类型
log<string[]>(['a', 'b']);
// 利用类型推论(推荐方式)
log(['a', 'b']);
泛型函数
我们不仅可以用泛型来定义一个函数,还定义一个函数类型
type Log = <T>(value: T) => T;
const myLog: Log = log;
泛型接口
泛型还可以用在接口中
interface Log {
<T>(value: T): T;
}
上面这里仅仅约束了一个函数,还可以用泛型来约束接口的其它成员,这样接口的所有成员都受到了泛型变量的约束。
interface Log<T> {
(value: T): T;
}
注意:当泛型变量约束了整个接口之后,在实现的时候必须指定一个类型
let myLog: Log<number> = log;
myLog(1);
如果不指定类型,也可以在接口的定义中,指定一个默认的类型
interface Log<T = string> {
(value: T): T;
}
let myLog: Log = log;
myLog('1');


















