前言
泛型
是为了构建通用化的组件所设计的,在强类型语言中,泛型
是构建大型复杂系统的主要特性之一,它允许将类型定义通用化,而不是单一的形式。
一、基本使用
function doSomeThing(arg: T): T {
return arg;
}
相比于我们之前学习的类型定义的方式,这里我们多了一个
,在TypeScript中,这就叫泛型
,表示的语义为,当你调用这个函数的时候除了传递常用的参数,你也可以传递类型,内部会使用传递的这个类型。
比如,我们传递一个string
类型:
doSomeThing("mss")
值得注意的是,当你使用了泛型
,TypeScript会默认会通过外部传入的类型,推断内部变量或者函数的返回值的类型,并且强制内部的类型要符合外部传入的类型,否则,TypeScript会报错:
function doSomeThing(arg: T): T {
console.log(arg.length)
return arg;
}
// Property 'length' does not exist on type 'T'
但是我们有的数据类型就是存在length
属性的,那我们这时应该怎么做呢?比如数组来说,TypeScript允许我们直接定义数组的泛型:
function deArr(arg: T[]): T[] {
console.log(arg.length);
return arg;
}
此时我们访问length
就是合法的。
同时,定义数组的泛型也可以这样写,这种方式和上面那种方式是等效的:
function deAnotherArr(arg: Array): Array {
console.log(arg.length);
return arg
}
这种方式也是可以,完全取决于你个人的喜好。
二、使用泛型类型
基本使用
function doSomeThing(arg: T): T {
console.log(arg.length)
return arg;
}
let myDoSomeThing: (arg: T) => T = doSomeThing;
传入的类型参数,也可以不用和函数定义的T
保持一致:
let myDoSomeThing: (arg: U) => U = doSomeThing;
这样也是可以的。
三、泛型接口
基本使用:
我们首先定义一个泛型
接口:
interface GenericInterFace {
(arg: T): T
}
然后我们这样使用:
let genericInterFace: GenericInterFace = function get(arg: T):T {
return arg;
}
也可以在定义接口的时候将传入泛型
的类型:
interface GenericInterFace {
(arg: T): T
}
使用的方式和上面的例子一样:
let genericInterFace: GenericInterFace = function get(arg: T):T {
return arg;
}
此外,前面的例子里面,当我们使用泛型
的时候,由于TypeScript编译器不能推断传入的T
的类型,当然这也不可能推断,所以当我们试图在内部访问length
属性的时候,就会报错。然后,我们这里可以利用接口,在编译之前就给开发一个友好的提示:
定义一个length
的接口:
interface Lengthwise {
length: number;
}
然后重写我们前面的doSomeThing
例子:
function doSomeThing(arg: T): T {
console.log(arg.length)
return arg;
}
此时就不会报错,这里已经确保了传入的参数必定是有length
属性的。
四、泛型类
泛型
类在结构上和泛型
接口差不多。
class GenericClass {
name: T
add: (x: T, y:T) => T
}
然后我们可以正常的通过new
关键字进行实例化。
let genericClass = new GenericClass();
genericClass.name = 'mss';
当然,使用泛型
的一个好处就是你可以传入任意类型的类型参数:
let genericClass = new GenericClass();
这也是合理的。
五、泛型的高级用法
1、使用泛型确保访问对象时不会访问到对象不存在的属性。
定义一个泛型
:
function getProperty(obj: T, key: K) {
return obj[key];
}
注意这里是的keyof
是TypeScript中给我们提供的遍历对象属性值的操作符。
然后我们这样使用:
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "a");
// 1
getProperty(x, "m");
// Argument of type '"m"' is not assignable to parameter of type '"a" | "b" | "c" | "d"'.
2、类的构造函数和泛型
一起使用
function create(c: { new (): T }): T {
return new c();
}