0%

泛型

用来创建可复用组件的工具,我们称之为泛型(generics)。利用泛型,我们可以创建一个支持众多类型的组件,这让用户可以使用自己的类型消费(consume)这些组件

泛型类型变量

1
2
3
4
function identity<Type>(arg:Type):Type{
return arg;
}
let output=identity<string>("myString");//let output:string

Type允许我们捕获用户提供的类型,使得我们接下来可以使用这个类型。调用函数里的<>明确设置Type为string作为函数调用的一个参数

或者直接使用类型参数推断

1
let output=identity("myString")

假如我们要使用arg的.length属性,如果传进的参数不拥有length属性,则会报错,有两种写法:

使用Type类型的数组而不是Type

1
2
3
4
function loggingIdentity<Type>(arg:Type[]):Type[]{
console.log(arg.length);
return arg;
}

泛型函数loggingIdentity接受一个Type类型参数和一个实参arg,实参arg是一个Type类型数组,该函数返回一个Type类型数组,使用类型变量Type,作为我们使用类型的一部分,而不是之前的一整个类型

1
2
3
4
function loggingIdentity<Type>(arg:Array<Type>):Array<Type>{
console.log(arg.length);
return arg;
}

泛型接口

泛型函数作为接口的函数

1
2
3
4
5
6
7
interface GenericIdentityfn{
<Type>(arg:Type):Type;
}
function identity<Type>(arg:Type):Type{
return arg;
}
let myidentity:GenericIdentityfn=identity;

有时,我们会将泛型参数作为整个接口的参数,可以让我们清楚知道传入的是什么参数(GenericIdentityfn而不是GenericIdentityfn),而且接口里的其他成员也可以看到

1
2
3
4
5
6
7
interface GenericIdentityfn{
(arg:Type):Type;
}
function identity<Type>(arg:Type):Type{
return arg;
}
let myidentity:GenericIdentityfn<number>=identity;

泛型类

类似于泛型接口,下面这个例子,不仅可以使用number类型,也可以使用其他类型,和接口一样,可以把类型参数放在类上,确保类中所有属性使用相同类型

一个类有两部分:静态部分和实例部分,泛型类仅仅对实例部分生效,静态成员不能使用类型参数

1
2
3
4
5
6
7
8
9
class GenericNumber<NumType>{
zeroValue:NumType;
add:(x:NumType,y:NumType)=>NumType;
}
let myGenericNumber=new GenericNumber<number>();
myGenericNumber.zeroValue=0;
myGenericNumber.add = function (x, y) {
return x + y;
};

泛型约束

在接口中列出约束条件,然后使用接口和extends关键词实现约束

1
2
3
4
5
6
7
interface Lengthwise {
length:number;
}
function loggingIdentity<Type extends Lengthwise>(arg:Type):Type{
console.log(arg.length);
return arg;
}

使用类型参数约束另一个类型参数

要获取一个对象给定属性名的值,我们需要确保我们捕获获取obj上不存在的属性,所以在两个类型之间建立一个约束:

1
2
3
4
5
6
7
function getProperty<Type,Key extends keyof Type>(obj:Type,key:Key){
return obj[key];
}
let x={a:1,b:2,c:3,d:4};
getProperty(x,'a');
getProperty(x,'m');
// Argument of type '"m"' is not assignable to parameter of type '"a" | "b" | "c" | "d"'.

在泛型中使用类

在TypeScript,当使用工厂模式创建实例时,有必要通过他们的构造函数推断出类的类型

1
2
3
function create<Type>(c:{new():Type}):Type{
return new c();
}

参考:

https://www.typescriptlang.org/docs/handbook/2/generics.html

https://ts.yayujs.com/handbook/Generics.html#%E6%B3%9B%E5%9E%8B-generics