TS进阶笔记 | 青训营笔记

62 阅读4分钟

一、Typescript泛型的基础知识

Typescript 中的泛型(Generics)可以帮助我们编写更加通用和灵活的代码。泛型可以让我们编写一个函数、类或接口,而不需要指定具体的数据类型,而是在使用的时候再根据具体的数据类型来确定。

下面是一个简单的例子,展示了如何在函数中使用泛型:


function identity<T>(arg: T): T {
  return arg;

}
let result1 = identity<string>("hello");
let result2 = identity<number>(123);

在上面的例子中,identity 函数接受一个泛型类型的参数 arg,并返回同样的类型。当我们在调用函数时,需要指定具体的类型参数,例如 stringnumber。如果我们没有指定类型参数,则 Typescript 会根据传入的参数自动推断出类型。

另外,我们还可以使用泛型来创建类或接口。下面是一个使用泛型的简单接口:


interface Pair<T, U> {
  first: T;
  second: U;

}
let pair: Pair<number, string> = { first: 1, second: "two" };

在上面的例子中,我们定义了一个 Pair 接口,它包含两个类型参数 TU,分别表示这个 Pair 对象的第一个和第二个元素的类型。我们可以使用具体的类型参数来实例化这个接口,例如 numberstring

二、泛型的高级应用

泛型不仅可以用于函数和接口,还可以用于类和类型别名,以及许多其他的高级用途。下面是一些常见的泛型高级应用:

  1. 类型约束

在函数中使用泛型时,我们可以对泛型类型进行约束,以确保类型符合某些特定的要求。下面是一个使用泛型类型约束的例子:


interface HasLength {
  length: number;

}
function printLength<T extends HasLength>(arg: T): void {
  console.log(arg.length);

}
printLength("hello");
printLength([1, 2, 3]);

在上面的例子中,我们定义了一个接口 HasLength,它包含一个 length 属性,用于表示对象的长度。在 printLength 函数中,我们使用了泛型类型约束 T extends HasLength,它表示泛型类型必须符合 HasLength 接口的要求。这样,我们就可以在函数中访问对象的 length 属性。

  1. 泛型类型推断

当我们在使用泛型时,Typescript 可以自动推断泛型类型,以避免我们手动指定类型参数。例如:

function identity<T>(arg: T): T {
  return arg;

}

let result = identity("hello"); // Typescript 会自动推断出 T 为 string 类型

  1. 泛型类

我们可以在类中使用泛型来定义类的属性、方法和构造函数等。下面是一个简单的泛型类的例子:


class Pair<T, U> {

  private first: T;
  private second: U;

  constructor(first: T, second: U) {
    this.first = first;
    this.second = second;

  }

  public getFirst(): T {
    return this.first;

  }

  public getSecond(): U {
    return this.second;

  }

}

let pair = new Pair<number, string>(1, "two");
console.log(pair.getFirst()); // 输出 1
console.log(pair.getSecond()); // 输出 "two"

在上面的例子中,我们定义了一个泛型类 Pair,它包含两个类型参数 TU,分别表示这个 Pair 对象的第一个和第二个元素的类型。在类的构造函数中,我们使用具体的类型参数来实例化这个类,例如 numberstring

  1. 泛型条件类型

泛型条件类型是一种高级的泛型类型,它可以基于某些条件来计算出最终的类型。下面是一个简单的泛型条件类型的例子:


type MyExclude<T, U> = T extends U ? never : T;
type Result = MyExclude<"a" | "b" | "c", "a" | "c">;
// Result 的类型为 "b"

在上面的例子中,我们定义了一个泛型条件类型 MyExclude<T, U>,它接受两个类型参数 TU,并根据某些条件计算出最终的类型。在 Result 类型中,我们使用了 MyExclude 类型,它表示排除了字符串类型 "a""c",剩下的类型为 "b"

  1. 泛型参数默认值

我们可以为泛型参数提供默认值,以避免在使用泛型时必须手动指定类型参数。下面是一个简单的泛型参数默认值的例子:


function identity<T = any>(arg: T): T {
  return arg;

}

let result1 = identity("hello"); // Typescript 会自动推断出 T 为 string 类型
let result2 = identity<number>(123); // 指定类型参数为 number

在上面的例子中,我们为泛型参数 T 提供了默认值 any,这样在使用泛型时如果没有手动指定类型参数,Typescript 会自动推断出类型为 any。但是如果我们手动指定了类型参数,例如 number,则默认值将被覆盖。

三、总结

泛型是 Typescript 中非常重要的一个特性,它可以帮助我们编写更加通用和灵活的代码。在使用泛型时,我们需要注意一些常见的技巧和高级用法,例如类型约束、类型推断、泛型类、泛型条件类型和泛型参数默认值等。