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、泛型约束
看一个想访问arg
的length
属性,但是编译器并不能证明每种类型都有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!