TypeScript 泛型


作者:Seiya

时间:2019年08月02日


前言


软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。

在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。




泛型


泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。


function identity<T>(arg: T): T {
	return arg;
}

这个版本的 identity 函数叫做泛型,因为它可以适用于多个类型。不同于使用any,它不会丢失信息,传入数值类型并返回数值类型。


定义了泛型函数后,可以用两种方法使用:

  • 传入所有的参数,包含类型参数:
let output = identity<string>("myString");  // type of output will be 'string'

  • 利用了类型推论,自动地帮助确定T的类型:
let output = identity("myString");  // type of output will be 'string'

tips

没必要使用尖括号 < > 来明确地传入类型;编译器可以查看myString的值,然后把T设置为它的类型。 类型推论帮助我们保持代码精简和高可读性。




多个类型参数


定义泛型的时候,可以一次定义多个类型参数:

function swap<T, U>(tuple: [T, U]): [U, T] {
	return [tuple[1], tuple[0]];
}

swap([7, 'seven']); // ['seven', 7]



泛型约束


在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法:

function loggingIdentity<T>(arg: T): T {
	console.log(arg.length);		// error
	return arg;
}

这个例子中,泛型 T 不一定包含属性 length,所以编译的时候报错了。


这时,我们可以对泛型进行约束,只允许这个函数传入那些包含 length 属性的变量。这就是泛型约束:

interface Lengthwise {
	length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
	console.log(arg.length);
	return arg;
}

上例中,使用了 extends 约束了泛型 T 必须符合接口 Lengthwise 的形状,也就是必须包含 length 属性。




泛型接口


我们可以使用含有泛型的接口来定义函数的形状:

interface CreateArrayFunc {
	<T>(length: number, value: T): Array<T>;
}

let createArray: CreateArrayFunc;
createArray = function<T>(length: number, value: T): Array<T> {
	let result: T[] = [];
	for (let i = 0; i < length; i++) {
			result[i] = value;
	}
	return result;
}

createArray(3, 'x'); // ['x', 'x', 'x']



泛型类


与泛型接口类似,泛型也可以用于类的类型定义中:

class GenericNumber<T> {
	zeroValue: T;
	add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };



泛型参数的默认类型


在 TypeScript 2.3 以后,我们可以为泛型中的类型参数指定默认类型。当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推测出时,这个默认类型就会起作用。

function createArray<T = string>(length: number, value: T): Array<T> {
	let result: T[] = [];
	for (let i = 0; i < length; i++) {
		result[i] = value;
	}
	return result;
}
最后更新时间: 2019-8-2 13:05:05