泛型表示可以接收得数据类型。使用泛型可以创建可重用得组件
我们来用any定义函数

  1. function identity(arg: any): any {
  2. return arg;
  3. }

使用any类型会导致整个函数可以接受任何arg参数,这样就丢失一些信息,传入的类型与返回得类型是相同的,但是如果我们使用any,返回的值可能会是任意类型.因此我们需要一种方法使传入得参数和返回得参数相同。这是泛型就派上用场了。

  1. function identity<T>(arg: T): T {
  2. return arg;
  3. }

这就是泛型,T 是我们传入的参数类型,使用这个之后我们就可以再次使用T当作返回值类型。我们就可以知道参数类型和返回类型了。

泛型使用方法

第一种,传入所有的参数,包括函数类型

  1. let output = identity<string>("myString"); // type of output will be 'string'

这里指明T类型是string类型,并作为第一个参数传给函数。
第二种方法,利用类型推论,会自动确定T得类型

  1. et output = identity("myString")

泛型变量

在使用泛型创建泛型函数时,编译器要求你在函数体中必须正确使用这个通用类型。例如上面那个identity函数可以是任意类型,如果我们想要打出arg.length 就会报错,因为他不具备length这个属性。
使用泛型变量创建数组

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

泛型类型

泛型函数的类型与非泛型函数的类型没什么不同,只是有一个类型参数在最前面,像函数声明一样

  1. function identity<T>(arg: T): T {
  2. return arg;
  3. }
  4. let myIdentity: <T>(arg: T) => T = identity;

使用不同得泛型参数名,只要数量一致即可

  1. function identity<T>(arg: T): T {
  2. return arg;
  3. }
  4. let myIdentity: <U>(arg: U) => U = identity;

使用带有调用签名得对象字面量来定义泛型函数:

  1. function identity<T>(arg: T): T {
  2. return arg
  3. }
  4. let myiden: { <T>(arg: T): T } = identity

使用泛型接口,把上面得字面量拿出来作为接口使用:

  1. interface myidenint<T> {
  2. (arg: T): T
  3. }
  4. function identity<T>(arg: T): T {
  5. return arg
  6. }
  7. let myiden: myidenint<number> = identity

泛型类

可以创建泛型类,但是无法创建泛型枚举和泛型命名空间
泛型类看上去与泛型接口差不多。 泛型类使用( <>)括起泛型类型,跟在类名后面。

  1. class GenericNumber<T> {
  2. zeroValue: T;
  3. add: (x: T, y: T) => T;
  4. }
  5. let myGenericNumber = new GenericNumber<number>();
  6. myGenericNumber.zeroValue = 0;
  7. myGenericNumber.add = function(x, y) { return x + y; };
  8. //官网得例子,实际的话会产生错误,个人认为 如果GenericNumber只是一个值得话就固定了参数类型,所以无需使用泛型类
  9. 稍微修改一下,就不会报错了
  10. class GenericNumber<T> {
  11. zeroValue: Array<T> =[];
  12. }
  13. 或者改正下面这个样子
  14. class GenericNumber<T> {
  15. zeroValue: T ;
  16. constructor(message:T){
  17. this.zeroValue = message
  18. }
  19. }
  20. let myGenericNumber = new GenericNumber<number>(1);
  21. myGenericNumber.zeroValue = 0;

泛型约束

如果我们想操作某个类得一组值,但是我不知道这个组值都具有什么样得属性,如果我们想要访问arg.length属性,但是编译器并不确定有所以就会报错

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

我们想要限制函数去处理任意带有 .length属性得所有类型,只要传入的类型有这个属性,也就是说至少包含这一属性。即可
所以我们定义一个接口来描述约束条件,使用extends 关键子来实现约束

  1. interface Lengthwise {
  2. length: number;
  3. }
  4. function loggingIdentity<T extends Lengthwise>(arg: T): T {
  5. console.log(arg.length); // Now we know it has a .length property, so no more error
  6. return arg;
  7. }

这个泛型函数就被定义约束了,因此不再适用于任何类型了,只有带.length 属性才可以

  1. loggingIdentity(3) //error 缺少length属性
  2. loggingIdentity({length: 10, value: 3}); //ok

在泛型约束中使用类型参数

你可以声明一个类型参数,且它被另一个类型参数所约束。 比如,现在我们想要用属性名从对象里获取这个属性。 并且我们想要确保这个属性存在于对象 obj上,因此我们需要在这两个类型之间使用约束

  1. function getProperty<T, K extends keyof T>(obj: T, key: K) {
  2. return obj[key]
  3. }
  4. let x = { a: 1, b: 2, c: 3, d: 4 };
  5. getProperty(x, "a"); // okay
  6. getProperty(x, "m"); //error
  7. 注意:如果function getProperty<T, K >报错, 类型“K”无法用于索引类型“T
  8. 个人理解就是K 没有T需要的属性,所以需要 K extends keyof T 继承一下,拿到属于obj的索引即可
  9. function asd<T>(params:T,K:keyof T) {
  10. return params[K]
  11. }
  12. let obj = {
  13. x:1,
  14. y:2
  15. }
  16. asd<typeof obj>(obj,'x')
  17. 上面哪种方法也可以改造一下

keyof: TypeScript 允许我们遍历某种类型的属性,并通过 keyof 操作符提取其属性的名称

  1. interface Person {
  2. name: string;
  3. age: number;
  4. location: string;
  5. }
  6. type K1 = keyof Person; // "name" | "age" | "location"

知识总结:

  1. 1.在一组<> 尖括号内并传入数据类型供函数接收这就叫泛型
  2. function identity<T>(arg: T): T {
  3. return arg;
  4. }
  5. 2.泛型变量
  6. function loggingIdentity<T>(arg: T): T {
  7. console.log(arg.length); // Error: T doesn't have .length
  8. return arg;
  9. }
  10. T 就是泛型变量
  11. 3.泛型类型
  12. let myIdentity: <T>(arg: T) => T = identity;
  13. <T>(arg: T) => T 就是泛型类型
  14. 也可用字面量来定义。
  15. let myIdentity: {<T>(arg: T): T} = identity;
  16. 或者使用泛型接口
  17. interface GenericIdentityFn<T> {
  18. (arg: T): T;
  19. }
  20. 4.泛型类
  21. class GenericNumber<T> {
  22. zeroValue: T ;
  23. constructor(message:T){
  24. this.zeroValue = message
  25. }
  26. }
  27. let myGenericNumber = new GenericNumber<number>(1);
  28. myGenericNumber.zeroValue = 0;
  29. 5.泛型约束
  30. interface Lengthwise {
  31. length: number;
  32. }
  33. function loggingIdentity<T extends Lengthwise>(arg: T): T {
  34. console.log(arg.length); // Now we know it has a .length property, so no more error
  35. return arg;
  36. }
  37. <T extends Lengthwise> 只要是有lenght属性的变量就可以,
  38. 6.在泛型约束中使用类型参数
  39. function getProperty<T, K extends keyof T>(obj: T, key: K) {
  40. return obj[key];
  41. }
  42. Tobj类型,k必须是t的索引类型才可以,所以用了K extends keyof T ,keyof T 读取T的索引,并由K继承此时不会报错