TypeScript学习之泛型(2)
泛型类型
实际上可以理解为,将泛型提取出来,作为一个通用类型。
通常,对于泛型函数的类型使用,可能是以下这种方式:(类型变量不一定是T,也可以是其他的名字)
function identity<T>(arg: T): T { return arg; } let myIdentity: <T>(arg: T) => T = identity; 复制代码
这种写法其实看上去会有点像js中使用箭头函数的形式去声明一个函数。
在TypeScript中,可以将箭头函数部分提取出来,作为一个接口,也就是泛型接口:
interface GenericIdentityFn { <T>(arg: T): T; } function identity<T>(arg: T): T { return arg; } let myIdentity: GenericIdentityFn = identity; 复制代码
如果把泛型参数当作整个接口的一个参数,即上述例子中GenericIdentityFn的参数T,这样就能清楚的知道使用的具体是哪个泛型类型,比如说,传入一个number:
interface GenericIdentityFn<T> { (arg: T): T } function identity<T>(arg: T): T { return arg; } let myIdentity: GenericIdentityFn<number> = identity; 复制代码
上述例子中,给接口传入了一个参数number,在使用的时候,就意味着使用的时候,这里的泛型类型就是number。
泛型类
除了泛型接口之外,还可以创建泛型类,和泛型接口差不多,泛型类使用<>包裹泛型类型,跟在类名后面。
class GenericNumber<T> ( zeroValue: T; add: (x: T, y: T) => T ) let mynericNumber = new GenericNumber<number>(); myGenericNumber.zeroValue = 0; myGenericNumber.add = function(x, y) { return x + y; } 复制代码
()中是泛型类型的参数列表,对于泛型类型,不一定是number,这也是个传参,同样可以传string等。像接口一样,将泛型类型放在类本身,可以确保类的所有属性都使用想用的类型,保证了类型的统一。
泛型约束
在有些情况下,编译器不能保证每种类型都会有某个属性存在,例如说number类型不存在length属性,但是又会需要去处理,相对于any,限制函数的处理或许是更好的办法。那么,就需要传入的类型中,有这个属性存在,因此,这便对泛型变量T产生了一个约束的概念。
定义一个接口来描述约束条件:
interface Lengthwise { length: number; } function loggingItentity<T extends Lengthwise>(arg: T): T { console.log(arg.length); return arg; } 复制代码
当泛型函数被定义了约束,便不再适用于任意类型。在使用中,必须传入符合约束类型的值:
loggingIdentity(3); // Error, number doesn't have a .length property loggingIdentity({length: 10, value: 3}) 复制代码
在泛型约束中使用类型参数
可以声明一个类型参数,且它被另一个类型参数所约束。举个例子来说,想从一个对象中获取一个属性,但是又需要确保取到的属性是存在的,这是,可以使用另外一个类型参数来约束这个行为。
function getProperty(obj: T, key: K) { return obj[key]; } let x = { a: 1, b: 2, c: 3, d: 4 }; getProperty(x, "a"); // okay getProperty(x, "m"); // error: Argument of type 'm' isn't assignable to 'a' | 'b' | 'c' | 'd'. 复制代码
在泛型里使用类类型
class BeeKeeper { hasMask: boolean; } class ZooKeeper { nametag: string; } class Animal { numLegs: number; } class Bee extends Animal { keeper: BeeKeeper; } class Lion extends Animal { keeper: ZooKeeper; } function createInstance<A extends Animal>(c: new () => A): A { return new c(); } createInstance(Lion).keeper.nametag; // typechecks! createInstance(Bee).keeper.hasMask; // typechecks!
作者:路过的前端小菜鸟
链接:https://juejin.cn/post/7032610487372251150