一文打通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 属性。要调用约束中的任何值,我们需要指定与该值关联的所有属性。

相关推荐
菌菇汤5 分钟前
uni-app实现单选,多选也能搜索,勾选,选择,回显
前端·javascript·vue.js·微信小程序·uni-app·app
Ramos丶13 分钟前
【ABAP】 从无到有 新建一个Webdynpro程序
java·前端·javascript
摸鱼仙人~22 分钟前
如何创建基于 TypeScript 的 React 项目
javascript·react.js·typescript
qq_4116719832 分钟前
vue3 的模板引用ref和$parent
前端·javascript·vue.js
清幽竹客2 小时前
vue-37(模拟依赖项进行隔离测试)
前端·vue.js
vvilkim2 小时前
Nuxt.js 页面与布局系统深度解析:构建高效 Vue 应用的关键
前端·javascript·vue.js
滿2 小时前
Vue3 父子组件表单滚动到校验错误的位置实现方法
前端·javascript·vue.js
专注VB编程开发20年2 小时前
javascript的类,ES6模块写法在VSCODE中智能提示
开发语言·javascript·vscode
夏梦春蝉3 小时前
ES6从入门到精通:模块化
前端·ecmascript·es6
拓端研究室4 小时前
视频讲解:门槛效应模型Threshold Effect分析数字金融指数与消费结构数据
前端·算法