Typescript 泛型类型如何工作

Typescript 泛型是一种获取具有参数的函数的方法,我们可以在调用该参数时定义该参数 – 就像我们可以在调用函数时更改函数的参数一样。

如果您不熟悉 Typescript 泛型的概念,请继续阅读以了解它们的工作原理。

Typescript 泛型如何工作#

想象一个像下面这样的函数 – 它有一个字符串类型的参数,并在其上输出一个字符串:

let myFunction = function(arg: string):string {
    return `Hello, the value of your argument is ${arg}`;
}
// This will return "Hello, the value of your argument is World"
myFunction("World");

有趣的是,myFunction两者都适用于多种类型,例如 astringnumber. 当我们在多种不同的情况下使某些东西工作时,它被称为泛型,而这正是Typescript 泛型的含义。

为了将我们的 Typescript 函数调整为泛型,我们在<>s 中直接在 function 关键字之后添加一个可定义的参数:

let myFunction = function<NewType>(arg: NewType):string {
    return `Hello, the value of your argument is ${arg}`;
}
// This will return "Hello, the value of your argument is World"
myFunction<number>(5);

将 Typescript 中的泛型参数视为与 vanilla Javascript 中的参数相同的方式。在上面的示例中,我们创建了一个新参数,称为NewType– 但您可以将其命名为任何名称。我们的论点arg是 类型NewType

然后,当我们调用 时myFunction(),我们可以定义参数的类型——在上面的例子中,是一个数字。

具有多种类型的泛型#

想象另一个例子,我们没有使用字符串字面量——在下面的例子中,我们简单地将两个参数相加:

let myFunction = function(x: string, y: string):string {
    return x + y;
}

// Returns HelloWorld
myFunction("Hello", "World");

同样,这适用于多种类型 – 最显着的是字符串和数字。让我们再次尝试添加一个泛型类型:

let myFunction = function<NewType>(x: NewType, y: NewType):number {
    return x.length + y.length;
}

除了这一次,我们会得到一个错误:


Property 'length' does not exist on type 'NewType'

这引发错误的原因是因为我们没有定义什么NewType可以做什么不能做什么。NewType为了解决这个例子,我们只需要使用[]括号提到 x 和 y 将是一个 s 数组:

let myFunction = function<NewType>(x: NewType[], y: NewType[]):number {
    return x.length + y.length;
}
// This will return 6 (3 + 3)
myFunction<number>([ 5, 6, 7 ], [ 10, 9, 8 ]);

扩展泛型类型

然而,有时我们会遇到不同的情况。我们可能会遇到想要扩展的情况NewType,例如,如果我们正在访问一个NewType应该具有但编译器不知道的属性。extends我们可以使用关键字扩展泛型类型。这意味着我们可以约束传递给函数的任何类型,因此它们具有最少的属性集。

在下面的示例中,所有类型的元素NewType都应至少具有以下属性name

type ExtendedNewType = {
    name: string
}

type User = {
    name: string,
    age?: number
}

// NewType must contain at least the attribute "name" - so lets add it as an extension of our ExtendedNewType type.
let myFunction = function<NewType extends ExtendedNewType>(x: NewType, y: NewType):string {
    return `${x.name} ${y.name}`
}
// This will return "Hello World"
let runFunction = myFunction<User>({ name: "Hello" }, { name: "World" });

自定义类型

我们在上面定义自定义类型。如果您不熟悉自定义类型,请尝试阅读我们在 Typescript 中创建自定义类型的指南

通用自定义类型#

除了将泛型类型应用于我们的函数之外,我们还可以将它们应用于我们自己的自定义类型。在下面的示例中,我们有一个 ID 可能是字符串或数字的用户。我们可以在新类型的顶层定义一个泛型类型,然后在我们使用该User类型时定义它。

// Type User can have an ID which is either a number or a string
type User<CustomType extends (number | string)> = {
    id: CustomType,
    name?: string,
    age?: number
}

// In this case, we define CustomType as a string
let myUser:User<string> = {
    id: "1234-1234-1234",
    name: "John Doe",
    age: 24
}

// In this case, we define CustomType as a number
let myOtherUser:User<number> = {
    id: 1234,
    name: "Jane Seymore",
    age: 48
}