0
点赞
收藏
分享

微信扫一扫

TypeScript 泛型


文章目录

  • ​​泛型简介​​
  • ​​泛型定义​​
  • ​​泛型使用​​
  • ​​1. 传入所有的参数,包含类型参数​​
  • ​​2. 类型推论​​
  • ​​3. 定义多个类型变量​​
  • ​​4. 使用泛型变量​​
  • ​​泛型接口​​

泛型简介

泛型在 TS 中可以说是一个非常重要的属性,它承载了从静态定义到动态调用的桥梁,同时也是 TS 对自己类型定义的元编程。泛型可以说是 TS 类型工具的精髓所在,也是整个 TS 最难学习的部分。

可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。

设计泛型的关键目的是在成员之间提供有意义的约束,这些成员可以是:类的实例成员、类的方法、函数参数和函数返回值。

泛型定义

下面来创建第一个使用泛型的例子:​​identity​​函数。 这个函数会返回任何传入它的值,不用泛型的话,这个函数可能是下面这样:

function identity(value:): any {
return value;
}

使用 ​​any​​ 类型会导致这个函数可以接收任何类型的参数,这样就丢失了一些信息:传入的类型与返回的类型应该是相同的。如果我们传入一个数字,我们只知道任何类型的值都有可能被返回。

因此,我们需要一种方法使返回值的类型与传入参数的类型是相同的。 这里,我们使用了 类型变量,它是一种特殊的变量,只用于表示类型而不是值。

function identity<T>(value: T): T {
return value;
}

我们给 ​​identity​​​ 添加了类型变量 ​​T​​​。 ​​T​​​ 帮助我们捕获用户传入的类型(比如:number),之后我们就可以使用这个类型。 之后我们再次使用了 ​​T​​ 当做返回值类型。现在我们可以知道参数类型与返回值类型是相同的了。 这允许我们跟踪函数里使用的类型的信息。

TypeScript 泛型_类型变量

我们把这个版本的 ​​identity​​ 函数叫做泛型,因为它可以适用于多个类型。 不同于使用 ​​any​​,它不会丢失信息,像第一个例子那像保持准确性,传入数值类型并返回数值类型。

泛型使用

我们定义了泛型函数后,可以用两种方法使用。

1. 传入所有的参数,包含类型参数

function identity<T>(value: T): T {
return value;
}

let output = identity<string>("myString");

这里调用函数我们明确的指定了 ​​T​​​ 是 string类型(​​identity<string>​​​),
这时 函数入参(value) 和 函数返回值 也必须都是 string类型,否则就会报错。

2. 类型推论

编译器会根据传入的参数自动地帮助我们确定 ​​T​​ 的类型 (普遍使用)

TypeScript 泛型_类型变量_02

这里调用函数我们没有使用尖括号(​​<>​​​)来明确地传入类型,
这时编译器可以自动推论出 ​​​myString​​​ 的类型,然后把 ​​T​​ 设置为它的类型。

类型推论帮助我们保持代码精简和高可读性。如果编译器不能够自动地推断出类型的话,只能像上面那样明确的传入 ​​T​​ 的类型,在一些复杂的情况下,这是可能出现的。

3. 定义多个类型变量

其实并不是只能定义一个类型变量,我们可以引入希望定义的任何数量的类型变量。
比如我们引入一个新的类型变量 ​​​U​​​,用于扩展我们定义的 ​​identity​​ 函数:

function identity <T, U>(value: T, message: U) : T {
console.log(message);
return value;
}

console.log(identity<Number, string>(68, "Semlinker"));

TypeScript 泛型_泛型_03


利用上面 ​​类型推论

identity<Number, string>(68, "Semlinker");
// 可省略尖括号,简写为:
identity(68, "Semlinker");

4. 使用泛型变量

如果我们想同时打印出 value 的长度。 我们很可能会这样做:

function identity<T>(value: T): T {
console.log(value.length); // 报错:类型 “T” 上不存在属性 “length”
return value;
}

如果这么做,编译器会报错说 ​​类型 “T” 上不存在属性 “length”​​​ ,但是没有地方指明 value 具有这个属性。
记住,这些类型变量代表的是任意类型,所以使用这个函数的人可能传入的是个数字,而数字是没有 ​​​.length​​属性的。

此时,我们可以将 ​​T​​​ 进一步设置成 ​T 类型的数组 即可:

function identity<T>(value: T[]): T[] {
console.log(value.length);
return value;
}

泛型函数​​identity​​​,接收​​类型参数 T​​​ 和 ​​参数 value​​​,此时参数和返回值是 ​T 的数组
这可以让我们把泛型变量 ​​​T​​ 当做类型的一部分使用,而不是整个类型,增加了灵活性。

泛型接口

interface Identities<V, M> {
value: V;
message: M;
}

function identity<T, U>(value: T, message: U): Identities<T, U> {
let identities = {
value,
message,
};
return identities;
}

identity(68, 'Semlinker'); // {value: 68, message: "Semlinker"}

在上述的 ​​Identities​​​ 接口中,我们引入了类型变量 ​​V​​​ 和 ​​M​​​,来进一步说明有效的字母都可以用于表示类型变量,之后我们就可以将 ​​Identities​​​ 接口作为 ​​identity​​ 函数的返回类型


举报

相关推荐

0 条评论