TypeScript 泛型的工作原理
Typescript 泛型是一种获取具有参数的函数的方法,我们可以在调用该参数时定义该参数 – 就像我们可以在调用函数时更改函数的参数一样。
如果不熟悉 Typescript 泛型的概念,请继续阅读来了解它们的工作原理。
Typescript 泛型如何工作
想象一个像下面这样的函数 – 它有一个字符串类型的参数,并在其上输出一个字符串:
let myFunction = function(arg: string):string {
return `Hello, 您的参数的值是 ${arg}`;
}
// 这将返回“您好,您的参数的值是 World”
myFunction("World");
有趣的是,myFunction 可以处理多种类型,例如字符串或数字。 当我们在多种不同的情况下使某些东西工作时,它被称为泛型,而这正是 Typescript 泛型的含义。
为了将我们的 Typescript 函数调整为通用函数,我们在 <>
中直接在 function
关键字之后添加一个可定义的参数:
let myFunction = function<NewType>(arg: NewType):string {
return `Hello, 参数的值是 ${arg}`;
}
// 将返回 "Hello, 参数的值是 5"
myFunction<number>(5);
将 Typescript 中的泛型参数视为与 vanilla Javascript 中的参数相同的方式。 在上面的示例中,我们创建了一个名为 NewType
的新参数 – 但我们可以将其命名为任何名称。 我们的参数 arg 是 NewType
类型。
然后,当我们调用 myFunction()
时,我们可以定义参数的类型——在上面的例子中,是一个数字。
具有多种类型的泛型
想象另一个例子,我们没有使用字符串字面量——在下面的例子中,我们简单地将两个参数相加:
let myFunction = function(x: string, y: string):string {
return x + y;
}
// 返回 HelloWorld
myFunction("Hello", "World");
同样,这适用于多种类型 – 最显著的是字符串和数字。 让我们再次尝试添加一个泛型类型:
Copylet myFunction = function<NewType>(x: NewType, y: NewType):number {
return x.length + y.length;
}
这会产生一个错误:
这引发错误的原因是因为我们还没有定义 NewType
可以做什么和不能做什么。 为了解决这个例子中的问题,我们只需要使用 [] 将 x 和 y 作为一个 NewTypes 数组:
let myFunction = function<NewType>(x: NewType[], y: NewType[]):number {
return x.length + y.length;
}
// 这将返回 6 (3 + 3)
myFunction<number>([ 5, 6, 7 ], [ 10, 9, 8 ]);
扩展泛型类型
然而,有时我们会遇到不同的情况。 我们可能会遇到想要扩展 NewType 的情况,例如,如果我们正在访问 NewType 应该具有但编译器不知道的属性。 我们可以使用 extends
关键字扩展泛型类型。 这意味着我们可以约束传递给函数的任何类型,因此它们具有最少的属性集。
在下面的示例中,NewType
类型的所有元素都应至少具有属性名称:
type ExtendedNewType = {
name: string
}
type User = {
name: string,
age?: number
}
// NewType 必须至少包含属性“name”——所以让我们将其添加为 ExtendedNewType 类型的扩展。
let myFunction = function<NewType extends ExtendedNewType>(x: NewType, y: NewType):string {
return `${x.name} ${y.name}`
}
// 这将返回 "Hello World"
let runFunction = myFunction<User>({ name: "Hello" }, { name: "World" });
泛型自定义类型
除了将泛型类型应用于我们的函数之外,我们还可以将它们应用于我们自己的自定义类型。 在下面的示例中,我们有一个 ID 可能是字符串或数字的用户。 我们可以在新类型的顶层定义一个泛型类型,然后在我们使用 User 类型时定义它。
// 类型用户可以有一个 ID,它可以是数字或字符串
type User<CustomType extends (number | string)> = {
id: CustomType,
name?: string,
age?: number
}
// 在这种情况下,我们将 CustomType 定义为字符串
let myUser:User<string> = {
id: "1234-1234-1234",
name: "John Doe",
age: 24
}
// 在这种情况下,我们将 CustomType 定义为一个数字
let myOtherUser:User<number> = {
id: 1234,
name: "Jane Seymore",
age: 48
}