TS(TypeScript)基础知识四:泛型

512 阅读3分钟

这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战

泛型是什么?为什么要用到泛型?来看几个例子

泛型函数

假设现在有一个需求:实现一个方法,传入的是什么类型参数,要求返回同样类型的值。比如传入字符串类型,返回的必须要是字符串类型; 首先我们可能会想到使用方法重载重载描述,定义出所有的可能性。 下面来看下方法重载的写法:

重载

	function reLoad(arg: string): string;
	function reLoad(arg: number): number;
			...
			...
	function reLoad(arg: any): any {
		return arg
	}

即使考虑的很全面,也有漏掉某些类型的可能。或者将来语法扩展多出了新的类型,又需要重新回来补齐。
而且这样的重载代码量很多,看起来很复杂;
如果使用any类型来限制,则无法达到需求。这个时候就可以用泛型来实现了:

泛型

来看一个例子:

function fn<T>(arg: T, arg2: string): T {
	return arg;
}
fn(1); 		
fn('123');
fn(true);

这里的就是泛指某种类型,并不是固定的。
他可以是string/number/boolean等等;你调用的时候传入的参数是什么类型,就会识别为什么类型。
上面的例子中第一次调用时传入的number类型,那就会识别为number类型。返回值也必须要是number类型。
注意:T只是约定俗称的,并不是一定要叫T。我们也可以改成U等其他的英文字母。

泛型接口;

将上面提到的泛型函数,改为接口来调用。看一下如何在接口中使用泛型:

方法一

interface InterFn {
	<T>(arg: T, arg2: string): T
}
let fn: InterFn = function (arg, arg2) {
	return arg
}
console.log(fn(1,''))
console.log(fn<number>(1,''))

除了类推方式调用fn方法,我们也可以直接指定<>内的类型。fn这个时候传入的参数就只能是number类型;

方法二

我们还可以前置泛型标识符

interface InterFn<T> {
	(arg: T, arg2: string): T
}
let fn: InterFn<string> = function (arg, arg2) {
	return arg
}
console.log(fn('1',''))
console.log(fn<string>('1',''))	//Expected 0 type arguments, but got 1

前置声明的接口,在引用接口声明函数时 则必须要给函数名声明泛型的具体类型。例:let fn: InterFn 调用方法的时候就必须要传入确实能够的类型,且不能在调用的时候变更类型。

方法三

下面这种方法,分别声明函数和调用的函数名。

interface InterFn<T> {
	(arg: T, arg2: string): T
}
function fn2<T>(arg: T, arg2: string) {
	return arg
}
let fn: InterFn<string> = fn2
console.log(fn2('1', ''))
console.log(fn2<number>(1, ''))
//
console.log(fn('1', ''))
console.log(fn<string>('1', ''))	//Expected 0 type arguments, but got 1

fn2方法为基础的调用方法。fn方法中使用了接口。是第二种方法的复杂写法
同样是前置了泛型类型,调用接口时声明了准确的类型。后面调用fn方法时不可再次修改类型。

泛型类

泛型考虑的是代码的重用性;及复用性;对不确定的数据类型的支持;

泛型类

class Cl<T>{
	list: T[] = [] 
	list2: Array<T> = []      
	run(arg: T): T {
		return this.list2[1];
	}
	run2: () => T
}

上面的例子中在类名后面添加了泛型的标识符,两个list都是泛型数组。方法也是泛型函数。

类替代接口

class Cl1{
        name:string | undefined;   
        pwd:string | undefined;
}
class Cl2<T>{				
        run(arg:T):any{           
                console.log(arg)
                return arg;
        }
}
let c1 = new Cl1();
c1.name = 'name';
//let c2 = new Cl2();
let c2 = new Cl2<Cl1>();
alert(c2.run(c1))

这个例子看到Cl1类被当作是接口来使用;接口和类都是对象,这部分基础阅读源码是足够了。有机会再拓展

TS(TypeScript)基础知识一:数据类型(变量)声明
TS(TypeScript)基础知识二:函数规范 、类
TS(TypeScript)基础知识三:接口(interface)