若是说接口和类是对一类事物的抽象描述,那么泛型能够说是对一类数据的抽象描述,进一步增强了语言的抽象程度,让组件重用性更好。 typescript
看一个小例子,实现数组的单条数据插入:数组
function insertTo<T>(array: T[], index: number, t: T): T[] { if (index < 0 || array.length - 1 < index) { throw new Error('Illegal index.'); } array.splice(index, 0, t); return array; } const arr1 = [1, 2, 4]; insertTo(arr1, 2, 3); console.log(arr1); const arr2 = ['a', 'b', 'd']; insertTo(arr2, 2, 'c'); console.log(arr2);
这个函数使用了泛型来表示传入参数的类型,咱们能够很明显感受到泛型的好处:一个函数就能够适配多种类型。用普通方式,咱们要重复这段逻辑写n个函数,用泛型一个就够用,这就是抽象的好处。函数
泛型能够用于函数,也能够用于类,还有更高级的用法:带限定的泛型。后面高级类型,还会用到泛型,会更复杂一些。学习
上面已给了一个例子,这里再补充一个用法,限定类型的泛型函数:this
interface GenericInsertFn<T> { <T>(array: T[], index: number, t: T): T[] } let myInsertTo: GenericInsertFn<number> = insertTo;
经过类型限定以后,咱们就获得了一个新的函数,这个函数只能操做数字类型的数组。code
泛型类和泛型函数用法相似,只是泛型声明在类上,整个类范围均可以用。
看个小例子:接口
class MyArrayList<T> { private _array: T[]; constructor() { this._array = []; } get lenght(): number { return this._array.length; } get(index: number): T { if (index < 0 || this._array.length - 1 < index) { throw new Error('Illegal index.'); } return this._array[index]; } push(...elements: T[]): number { return this._array.push(...elements); } insertTo(index: number, t: T): T[] { if (index < 0 || this._array.length - 1 < index) { throw new Error('Illegal index.'); } this._array.splice(index, 0, t); return this._array; } }
以上例子实现了一个简单的泛型的ArrayList,若是你熟悉Java语言,对此就不陌生了。实现的效果和函数相似,也是抽象和重用。ip
有的场景,泛型须要限定范围,好比一个任务执行者函数,须要接受实现了工做者接口的函数做为参数才能够执行,那么就须要带限定的泛型参数,看代码:element
interface IWorker { (task: string): number; } function excutor<W extends IWorker>(r: W) { r('case1'); } const myWorker: IWorker = function (task: string) { console.log(`${task} is start.`); return 1; } excutor(myWorker);
再看一个更复杂一点的用法,多重泛型,抽象度也更高,通用性也更好。get
interface IJobRunner<T, K> { run(t: T): K; } interface ITimeJobExcutor<T, K, R extends IJobRunner<T, K>> { excute(r: R): void; }
基本的泛型用法学习完了,后面高级类型还会继续学习更高级的用法。