泛型可以为函数、接口、类定义类型变量,这些类型变量就像真实存在的类型一样,可以用于注解值的类型,它的语法形式为:
名字<T1, T2, ...>
名字一般表示函数名、接口名、类名,T1, T2, ...
表示一个或多个名字任意的类型变量,实际开发中常常以首字母大写的标识符作为类型变量名。泛型在使用时必须以真实类型替换类型变量
// 定义泛型函数,类型变量为T
// T接下来在"参数、返回值、变量"定义中可以作为类型使用
function identity<T>(m: T): T {
// T 注解了函数内部的变量定义
let n: T = m;
return n;
}
// 调用泛型函数,此时用string类型替换类型变量 T
// identity<string> 作为一个整体相当于一个函数名
let m: string = identity<string>('hello world');
// 定义泛型类,包含两个类型变量
class Identity<T1, T2> {
attr1: T1;
attr2: T2;
show(m: T1, n: T2): T2{
return n;
}
}
// 用真实类型替换泛型类的类型变量
// Identity<string, number>作为一个整体相当于一个类名
let a: Identity<string, number>;
// 初始化变量a
a = new Identity<string, number>();
// T1=>string,T1被替换为string,属性attr1为字符串类型
a.attr1 = 'hello';
// T2=>number,T2被替换为number,属性attr2位数字类型
a.attr2 = 99;
// 错误,类型不匹配
// error TS2322: Type '"good"' is not assignable to type 'number'
a.attr2 = 'good';
// 定义泛型接口
interface Identity<T> {
attr: T;
}
// 用真实类型替换泛型接口的类型变量
// Identity<number>作为一个整体相当于一个接口名
let a: Identity<number> = {attr: 10};
// Identity<string>作为一个整体相当于一个接口名
let b: Identity<string> = {attr: 'hello'};
// 错误,类型不匹配,数字10是数字类型,而类型变量为布尔类型
// error TS2322: Type 'number' is not assignable to type 'boolean'.
let c: Identity<boolean> = {attr: 10};
// 一个复杂点的例子
function fn(){};
let c: Identity<typeof fn> = {
attr(){}
}