一文打通TypeScript 泛型

前言

人们经常听说 TypeScript 就是添加了类型和附加功能的 JavaScript,但却没有人谈论这些"附加功能",仿佛他们害怕自己会发现什么似的。为了提高应用程序的灵活性和长期可扩展性,泛型被引入 Web 开发中,作为一种工具来复用组件。

什么是 TypeScript 泛型?

这里有这样一个有趣的场景:一位 TypeScript 开发者正在和一位 JavaScript 开发者讨论他们在 Web 开发中最喜欢使用的功能。聊天中,他们提到了"泛型"这个词。JavaScript 开发者感到困惑,问泛型是什么。TypeScript 开发者回答说:" TypeScript 泛型是 Web 开发中用于创建可复用组件的工具。它可以帮助开发者创建能够处理多种数据类型的组件,而无需为特定组件显式定义每种类型。"

假设一位开发人员创建了一个特定类型的组件number,但之后在代码库中,他想复用该组件的功能来接受其他数据类型的输入,比如string。TypeScript 泛型无需切换组件来接受string数据类型,而是提供了为单个组件接受多种类型的灵活性。是不是很有意思?所以,如果你一直在寻找实现这一点的方法,那么你来对地方了!

为什么要使用 TypeScript 泛型?

代码可重用性是使用 TypeScript 泛型的好处之一,但这还不是全部。其他主要好处包括:

  • 编译时类型检查:使用泛型时,必须在定义变量、函数或类后指定数据类型。指定的数据类型会在到达编译器之前进行检查。这可以节省开发时间,因为类型错误会更早地被突出显示。
  • 提高代码可读性:在大型项目或团队合作中,一项关键的工程实践是确保代码易于阅读。由于 TypeScript 泛型是明确定义的,因此使用泛型可以提高代码可读性。
  • 消除类型推断: 泛型不再允许 TypeScript 编译器通过类型推断来推断类型,而是消除了类型推断的需要。这提高了代码安全性。
  • 消除 any 类型:确保变量兼容多种类型的一种方法是赋予其 any 类型。这会告诉编译器:"嘿,这个变量应该适用于任何数据类型!" 然而,这是一种不好的做法,因为没有进行类型检查,可能会导致不必要的结果。泛型提供了一种在确保类型安全的同时接受多种数据类型的方法。

基本语法和工作原理

我们已经了解到,使用泛型可以实现单个变量接受多种数据类型,而不像使用any关键字那样。考虑下面的代码块:

typescript 复制代码
// type of number is defined
let size: number = 12;
// size accept type of string?
let size = "Twelve";
// error

在上面的代码片段中,我们将变量 size 的类型指定为数值,其值为12,然后尝试将变量重新赋值为,但采用字符串格式。由于我们尝试将变量赋值为类型,而该变量最初被定义为接受数据类型12,因此会引发错误。我们如何实现一个实例,使变量能够同时接受和两种类型?string``Twelve``number``number``string

使用任何数据类型

将多种数据类型的值赋给单个变量的一种方法是使用any数据类型。请考虑下面的代码块:

ini 复制代码
//code sample
let sample: any;
//string data type
sample =
  "Convert from one programming language to another using the Pieces App";
//number data type
sample = 2;

sample = true;

在这里,我们创建一个名为 sample 的变量,其any类型为 。这意味着该变量可以接受任何数据类型。在我们的代码片段中,我们分配了一个string类型,表示"使用 Pieces App 从一种编程语言转换为另一种编程语言",一个number类型为 value 2,以及一个布尔类型为 value true

在 TypeScript 中,将其他数据类型的值赋给预定义变量会引发错误,但 TypeScriptany提供了解决方案。any然而,不建议使用 TypeScript 数据类型,因为它会绕过类型检查,并在运行时带来类型不匹配的风险。

泛型的使用 - 泛型函数

TypeScript 允许单个变量使用多种数据类型的另一种方式是使用泛型。泛型函数构成了泛型的主要用途。假设我们现在在 TypeScript 中创建一个接受数字类型的函数。具体操作如下:

lua 复制代码
function numberType(arg: number): number {
  return arg;
}

这里,为了避免抛出错误,返回值的类型必须是数字。有时,我们不知道返回的具体值。使用该any类型将使函数接受该值,但我们不知道返回的类型。这就是 TypeScript 中泛型的作用所在。它允许接受任何数据类型,同时指定被接受的类型。让我们看看如何实现这一点:

lua 复制代码
function anyType<Type>(arg: Type): Type {
  return arg;
}

在上面的代码片段中,我们添加了一个Type嵌入的 Type 变量<>,这是 TypeScript 泛型的基本语法。当函数返回一个值时,Type可以通过 知道返回的确切类型。这是使用 TypeScript 泛型的好处之一------不再需要any类型。

创建通用函数

为了正确理解代码库中泛型的必要性,我们将创建一个基本的 TypeScript 泛型函数,它接受不同类型的数据。正如我们之前讨论过的,实现这一点的一种方法是使用any类型。在本节中,我们将讨论如何使用泛型来实现这一点。请考虑下面的代码块:

typescript 复制代码
function genericsSample<T>(items: T[]): T[] {
  return new Array<T>().concat(items);
}
let numType = genericsSample<number>([10, 20, 30]);
let stringType = genericsSample<string>([
  "Pieces app",
  "A tool for developers",
]);
numType.push(80); // Correct
numType.push("Copy and save code snippets"); // Error
stringType.push(
  "Convert from one programming language to another using the Pieces App",
); // Correct
stringType.push(90); //Error
console.log(numType);
console.log(stringType);

在上面的代码块中,我们创建了一个用于连接两个元素的泛型函数。此代码片段旨在接受两种类型的数据:数字和字符串。此代码片段与包含泛型的代码片段的主要区别any在于,泛型函数会验证用户的数据类型。

在此代码片段中,我们创建了一个名为 的泛型函​​数genericsSample,它返回一个类型数组。之后,我们创建了两个变量,numType和接受一个数字数组,而接受一个字符串数组stringType。这样做的目的是在用户登录控制台之前验证用户的输入。numType``stringType

成功创建变量后,我们尝试向已创建的 TypeScript 通用数组中添加新项,以测试其是否有效。我们向 和 分别添加了一个字符串和一个数字numTypestringType这两个字符串分别是"复制并保存代码片段" 和"使用 Pieces App 从一种编程语言转换为另一种编程语言", 它们是 Pieces 的一些用例。

在输出中,我们看到,当我们尝试将字符串添加到 anumType以及尝试将数字添加到 a 时,它会抛出一个错误stringType。让我们运行代码并查看输出:

在这里,我们看到,第一次将字符串传递给 numType 变量时会引发一个错误,而将数字传递给 stringType 变量时又会引发另一个错误。借助泛型,我们的代码可以在单个函数中验证多种数据类型的输入。

泛型类

除了创建函数之外,我们还可以创建 TypeScript 泛型类。定义类名后,在尖括号 (<>) 中指定泛型类型参数。请考虑以下代码块:

typescript 复制代码
class GenericClass<T> {
  private genericField: T;

  constructor(value: T) {
    this.genericField = value;
  }

  getValue(): T {
    return this.genericField;
  }
}

//creating a class with a number type
const numType = new GenericClass<number>(27);
const getNum: number = numType.getValue();
console.log(getNum);

//creating a class with a string type
const stringType = new GenericClass<string>(
  "Convert from one programming language to another using the Pieces App",
);
const getString: string = stringType.getValue();
console.log(getString);

在这里,为了在我们的类中接受多种类型,我们在 TypeScript 中创建了一个泛型类,其类型参数为"T",这样我们就可以指定要传递给它的任何类型(数字、字符串或任何其他类型)。在这段代码的第一个实例中,我们指定 GenericClass 的值应该是数字类型 27。在第二个实例中,我们指定 GenericClass 的值应该是一个字符串,内容为"使用 Pieces App 从一种编程语言转换为另一种编程语言" 。

TypeScript 通用接口

TypeScript 中的接口也支持泛型。这使我们能够创建接受多种数据类型的接口。假设我们要创建一个接受两种类型(数字和字符串)的泛型 TypeScript 接口。操作方法如下:

sql 复制代码
interface interfaceSample<T, U> {
  first: T;
  second: U;
}

const interfaceOne: interfaceSample<number, string> = {
  first: 20,
  second: "10",
};
const interfaceTwo: interfaceSample<string, boolean> = {
  first: "Generate code snippets using Pieces Co Pilot",
  second: true,
};

console.log(interfaceOne);
console.log(interfaceTwo);

这里,我们创建一个 TypeScript 泛型接口,其中包含两个类型参数"T"和"U"。这代表我们将要传入的类型的占位符。在 interfaceOne 变量中,我们传入数字类型和字符串类型。在 interfaceTwo 变量中,我们传入一个布尔类型和一个字符串类型,其含义为"使用 Pieces Copilot 生成代码片段" 。

TypeScript 泛型约束

虽然泛型适用于所有类型,但有时我们可能希望将函数、类或接口限制为仅使用单一类型。我们通过使用 TypeScript 泛型约束来实现这一点。我们可以使用一个示例接口来演示这一点:

php 复制代码
interface ConstraintSample {
  sample: number;
}

function loggingIdentity<Type extends ConstraintSample>(test: Type): Type {
  console.log(test.sample); //
  return test;
}
loggingIdentity({ sample: 15, value: 10 });

通常,要获取值 10,我们只需调用 loggingIdentity(10) 函数即可,但在本例中,这行不通,因为我们添加了一个泛型约束,它为我们正在处理的类型增加了额外的特异性。在这里,要获取值 10,我们必须首先指定我们尝试调用的值中有一个 sample 属性。要调用约束中的任何值,我们需要指定与该值关联的所有属性。

相关推荐
加班是不可能的,除非双倍日工资2 小时前
css预编译器实现星空背景图
前端·css·vue3
wyiyiyi2 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
gnip3 小时前
vite和webpack打包结构控制
前端·javascript
excel3 小时前
在二维 Canvas 中模拟三角形绕 X、Y 轴旋转
前端
阿华的代码王国4 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
一条上岸小咸鱼4 小时前
Kotlin 基本数据类型(三):Booleans、Characters
android·前端·kotlin
Jimmy4 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
ZXT4 小时前
promise & async await总结
前端
Jerry说前后端4 小时前
RecyclerView 性能优化:从原理到实践的深度优化方案
android·前端·性能优化
画个太阳作晴天4 小时前
A12预装app
linux·服务器·前端