泛型表示可以接收得数据类型。使用泛型可以创建可重用得组件
我们来用any定义函数
function identity(arg: any): any {return arg;}
使用any类型会导致整个函数可以接受任何arg参数,这样就丢失一些信息,传入的类型与返回得类型是相同的,但是如果我们使用any,返回的值可能会是任意类型.因此我们需要一种方法使传入得参数和返回得参数相同。这是泛型就派上用场了。
function identity<T>(arg: T): T {return arg;}
泛型使用方法
第一种,传入所有的参数,包括函数类型
let output = identity<string>("myString"); // type of output will be 'string'
这里指明T类型是string类型,并作为第一个参数传给函数。
第二种方法,利用类型推论,会自动确定T得类型
et output = identity("myString")
泛型变量
在使用泛型创建泛型函数时,编译器要求你在函数体中必须正确使用这个通用类型。例如上面那个identity函数可以是任意类型,如果我们想要打出arg.length 就会报错,因为他不具备length这个属性。
使用泛型变量创建数组
function loggingIdentity<T>(arg: Array<T>): Array<T> {console.log(arg.length);return arg;}
泛型类型
泛型函数的类型与非泛型函数的类型没什么不同,只是有一个类型参数在最前面,像函数声明一样
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: <U>(arg: U) => U = identity;
使用带有调用签名得对象字面量来定义泛型函数:
function identity<T>(arg: T): T {return arg}let myiden: { <T>(arg: T): T } = identity
使用泛型接口,把上面得字面量拿出来作为接口使用:
interface myidenint<T> {(arg: T): T}function identity<T>(arg: T): T {return arg}let myiden: myidenint<number> = identity
泛型类
可以创建泛型类,但是无法创建泛型枚举和泛型命名空间
泛型类看上去与泛型接口差不多。 泛型类使用( <>)括起泛型类型,跟在类名后面。
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; };//官网得例子,实际的话会产生错误,个人认为 如果GenericNumber只是一个值得话就固定了参数类型,所以无需使用泛型类稍微修改一下,就不会报错了class GenericNumber<T> {zeroValue: Array<T> =[];}或者改正下面这个样子class GenericNumber<T> {zeroValue: T ;constructor(message:T){this.zeroValue = message}}let myGenericNumber = new GenericNumber<number>(1);myGenericNumber.zeroValue = 0;
泛型约束
如果我们想操作某个类得一组值,但是我不知道这个组值都具有什么样得属性,如果我们想要访问arg.length属性,但是编译器并不确定有所以就会报错
function loggingIdentity<T>(arg: T): T {console.log(arg.length); // Error: T doesn't have .lengthreturn 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 errorreturn arg;}
这个泛型函数就被定义约束了,因此不再适用于任何类型了,只有带.length 属性才可以
loggingIdentity(3) //error 缺少length属性loggingIdentity({length: 10, value: 3}); //ok
在泛型约束中使用类型参数
你可以声明一个类型参数,且它被另一个类型参数所约束。 比如,现在我们想要用属性名从对象里获取这个属性。 并且我们想要确保这个属性存在于对象 obj上,因此我们需要在这两个类型之间使用约束
function getProperty<T, K extends keyof T>(obj: T, key: K) {return obj[key]}let x = { a: 1, b: 2, c: 3, d: 4 };getProperty(x, "a"); // okaygetProperty(x, "m"); //error注意:如果function getProperty<T, K >报错, 类型“K”无法用于索引类型“T”个人理解就是K 没有T需要的属性,所以需要 K extends keyof T 继承一下,拿到属于obj的索引即可function asd<T>(params:T,K:keyof T) {return params[K]}let obj = {x:1,y:2}asd<typeof obj>(obj,'x')上面哪种方法也可以改造一下
keyof: TypeScript 允许我们遍历某种类型的属性,并通过 keyof 操作符提取其属性的名称
interface Person {name: string;age: number;location: string;}type K1 = keyof Person; // "name" | "age" | "location"
知识总结:
1.在一组<> 尖括号内并传入数据类型供函数接收这就叫泛型function identity<T>(arg: T): T {return arg;}2.泛型变量function loggingIdentity<T>(arg: T): T {console.log(arg.length); // Error: T doesn't have .lengthreturn arg;}T 就是泛型变量3.泛型类型let myIdentity: <T>(arg: T) => T = identity;<T>(arg: T) => T 就是泛型类型也可用字面量来定义。let myIdentity: {<T>(arg: T): T} = identity;或者使用泛型接口interface GenericIdentityFn<T> {(arg: T): T;}4.泛型类class GenericNumber<T> {zeroValue: T ;constructor(message:T){this.zeroValue = message}}let myGenericNumber = new GenericNumber<number>(1);myGenericNumber.zeroValue = 0;5.泛型约束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 errorreturn arg;}<T extends Lengthwise> 只要是有lenght属性的变量就可以,6.在泛型约束中使用类型参数function getProperty<T, K extends keyof T>(obj: T, key: K) {return obj[key];}T为obj类型,k必须是t的索引类型才可以,所以用了K extends keyof T ,keyof T 读取T的索引,并由K继承此时不会报错
