ts-泛型

1、泛型类型

首先先了解泛性函数

\\ 普通方法
function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: <T>(arg: T) => T = identity;

\\对象字面量的方法写函数

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

let myIdentity: {<T>(arg: T): T} = identity;// {<T>(arg: T): T}  ===  <T>(arg: T) => T

第一个泛型接口

interface GenericIdentityFn<T> {
    (arg: T): T;
}

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

let myIdentity: GenericIdentityFn<number> = identity;

或者

interface GenericIdentityFn {
    <T>(arg: T): T;
}

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

let myIdentity: GenericIdentityFn = identity;

2、泛型类

看上去与泛型接口差不多。 泛型类使用( <>)括起泛型类型,跟在类名后面。

let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = function(x, y) { return x + y; };

console.log(stringNumeric.add(stringNumeric.zeroValue, "test"));

3、泛型约束

看一个想访问arglength属性,但是编译器并不能证明每种类型都有length属性,所以就报错的例子

function loggingIdentity<T>(arg: T): T {
    console.log(arg.length);  // Error: T doesn't have .length
    return arg;
}

为此,我们定义一个接口来描述约束条件。 创建一个包含 .length属性的接口,使用这个接口和extends关键字来实现约束:

interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);  // Now we know it has a .length property, so no more error
    return arg;
}

//现在这个泛型函数被定义了约束,因此它不再是适用于任意类型:
loggingIdentity(3);  // Error, number doesn't have a .length property
//我们需要传入符合约束类型的值,必须包含必须的属性:
loggingIdentity({length: 10, value: 3});

4、在泛型约束中使用类型参数 === 官方不够语义化,其实就是泛型的入参也拥有类似函数入参的特性,参数之间可以互相约束


\\多个不同的泛型入参之间设置约束关系,如下代码所示:
interface ObjSetter {
  <O extends {}, K extends keyof O, V extends O[K]>(obj: O, key: K, value: V): V;
}

const setValueOfObj: ObjSetter = (obj, key, value) => (obj[key] = value);
setValueOfObj({ id: 1, name: 'name' }, 'id', 2);
setValueOfObj({ id: 1, name: 'name' }, 'name', 'newName');
setValueOfObj({ id: 1, name: 'name' }, 'age', 2);
setValueOfObj({ id: 1, name: 'name' }, 'id', '2');

\\泛型入参与函数入参还有一个相似的地方在于,它也可以给泛型入参指定默认值(默认类型)
interface ReduxModelSpecified<State extends { id: number; name: string }> {
  state: State
}
interface ReduxModelSpecified2<State = { id: number; name: string }> {
  state: State
}
type ComputedReduxModel5 = ReduxModelSpecified2;
type ComputedReduxModel6 = ReduxModelSpecified2<{ id: number; name: string; }>;
type ComputedReduxModel7 = ReduxModelSpecified; // ts(2314) 缺少一个类型参数

5、在泛型里使用类类型===语义化就是:函数传入类,实现函数的时候实例化这个类

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!


版权声明:本文为qq_39584251原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。