1.泛型是什么
泛型就是当你在写公用的组件或utils时,会不确定消费者(业务侧的数据类型),此时可以使用泛型来定义。
2.泛型的用途
在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。 不同于使用 any,它不会丢失信息。
eg.创建一个函数会返回任何传入它的值.
function identity(arg: any): any { return arg; }
使用any类型会导致这个函数可以接收任何类型的arg参数,这样就丢失了一些信息:传入的类型与返回的类型应该是相同的。如果我们传入一个数字,我们只知道任何类型的值都有可能被返回。
因此,我们需要一种方法使返回值的类型与传入参数的类型是相同的。 这里,我们使用了 类型变量,它是一种特殊的变量,只用于表示类型而不是值。
function identity<T>(arg: T): T { return arg; }
我们定义了泛型函数后,可以用两种方法使用。 第一种是,传入所有的参数,包含类型参数:
let output = identity<string>("myString"); // type of output will be 'string'
第二种方法更普遍。利用了类型推论 -- 即编译器会根据传入的参数自动地帮助我们确定T的类型:
let output = identity("myString"); // type of output will be 'string'
3.泛型在函数中的使用(泛型类型)
普通函数
见上面例子
匿名函数
const identit = <T>(arg:T):T => arg
可见,匿名函数配合箭头函数可以简化代码。
4.泛型在接口interface中的使用
interface GenericIdentityFn<T>
{
(arg: T): T;
}
function identity<T>(arg: T): T { return arg; }
let myIdentity: GenericIdentityFn<number> = identity;
泛型参数也可以定义多个
export interface AxiosResponse<T = any, D = any> {
data: T;
status: number;
statusText: string;
headers: RawAxiosResponseHeaders | AxiosResponseHeaders;
config: AxiosRequestConfig<D>;
request?: any;
}
5.泛型在类中的使用
泛型类看上去与泛型接口差不多。 泛型类使用( <>)括起泛型类型,跟在类名后面。
class GenericNumber<T> {
zeroValue: T; add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
泛型类指的是实例部分的类型,所以类的静态属性不能使用这个泛型类型。
6.泛型约束:当泛型被定义了约束时就不再适用于任意类型了
创建一个包含 .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});
7.在泛型约束中使用类型参数(使用keyof约束对象)
你可以声明一个类型参数,且它被另一个类型参数所约束。 比如,现在我们想要用属性名从对象里获取这个属性。 并且我们想要确保这个属性存在于对象 obj上,因此我们需要在这两个类型之间使用约束。