0.泛型基本用法:
- 在软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。组件不仅能支持当前数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能
- 简而言之:泛型就是解决 类、接口、方法的复用性,以及对不特定数据类型的支持
在ts中,比如一个函数要支持传入类型与返回类型支持多种数据类型,可以使用any,any就是完全放弃了数据类型检查
ts中的泛型:<T>
可以支持不特定的数据类型
示例1:要求,传入的参数和返回的参数一致
function getData<T>(value: T): T { return value; } // 类型检查和传入参数必须一致 console.log(getData<number>(123)); console.log(getData<string>('abc'));
示例2:返回数组的两个值
function swap<T, U>(tuple: [T, U]): [U, T] { return [tuple[1], tuple[0]] } const result = swap([123, 'abc']) result[1].toFixed(2)
可以把它看成一个占位符,使用的时候才动态的填入类型值
1.约束泛型
有时对某个类型的泛型要调用该泛型内的方法,例如:
function echoWithArr<T>(arg: T): T { console.log(arg.length) return arg }
如果此时传入的是number类型的参数,就没有length属性,且会提示:
这里可以使用泛型约束了
function echoWithArr<T>(arg: T[]): T[] { console.log(arg.length) return arg } const arr = echoWithArr([1, 2, 3])
上面代码中约束了传入的参数需要是任意类型的数组,但是,Object,String类型都是有length属性的,这时候就不满足这种场景了。这时候需要对泛型进行约束,允许这个函数传入包含length属性的变量(约束泛型):
interface IWithLength { length: number } function echoWithLength<T extends IWithLength>(arg: T): T { console.log(arg.length) return arg } const len01 = echoWithLength('abc') // 3 const len02 = echoWithLength({ length: 12 }) // 12 const len03 = echoWithLength([1, 2, 3]) // 3
上面代码中,定义了一个接口IWithLength,在函数echoWithLength的泛型中使用extends关键字继承自这个接口,表示这个泛型必须要有length这个属性。
2.泛型类:
如有个方法,需要同时支持返回字符串和数字两种类型,需要通过泛型类来实现
class MinClass<T>{ public list: T[] = []; add(value: T): void { this.list.push(value); } min(): T { let minNum = this.list[0]; for (let e of this.list) { if (minNum > e) { minNum = e } } return minNum; } } // 制定类的代表类型是number let m = new MinClass<number>(); //实例化类,并且制定了类的代表类型是number m.add(5); m.add(9); m.add(12); m.add(4); console.log(m.min()); // 制定类的代表类型是number let m1 = new MinClass<string>(); m1.add('d'); m1.add('f'); m1.add('z'); m1.add('q'); console.log(m1.min());
3.泛型接口
先看看函数类型接口:
interface ConfigFn{ (value1:string,value2:string):string; } let setData:ConfigFn=function(v1:string,v2:string):string{ return v1+v2; } setData('name','张三');
未完待续。。