为了账号安全,请及时绑定邮箱和手机立即绑定

TypeScript 泛型详解:灵活编写可重用代码的方法

简而言之: TypeScript 泛型让开发人员能够编写适用于多种数据类型的可重用代码,同时确保类型安全。它们对于构建既稳健又可扩展的 TypeScript 应用程序至关重要。

TypeScript 泛型](https://imgapi.imooc.com/677b513108223cae08000442.jpg)为了使代码更透明和易于管理,TypeScript 需要安全且有效地管理各种数据类型。TypeScript 的核心特性之一是 TypeScript 泛型,它可以创建函数、类和接口,并严格遵循类型限制。泛型可以让你用更少的代码犯更少的错误,最重要的是,构建适用于不同类型数据的灵活组件。

本文探讨了 Typescript 泛型的基本概念,包括如何在函数、类和接口中使用它们,并展示了它们是如何让代码变得更加灵活和健壮的。

TypeScript 泛型是什么?

TypeScript 泛型(TypeScript 泛型)可以定义带有占位符类型的 TypeScript 代码,从而在保持类型安全的前提下,使代码更加灵活、可扩展和可重用。

TypeScript 在编译时通过一个定义泛型类型的占位符来进行类型安全性检查。当实现组件时,实际类型会替换占位符。这使得管理类型和减少重复变得更加简单,因此你不需要针对每种数据类型写出不同的实现。

没有泛型,你将不得不为处理不同数据类型编写多个版本的函数或类,这会导致代码重复。泛型让你能够编写一个单一版本,这个版本可以适用于多种类型,并保持静态类型检查。

接下来的代码示例将帮助你理解这种差异。

什么时候用 Typescript 泛型?

泛型可以在TypeScript的不同部分使用,以更有效地管理类型。它们在函数、接口、类和其他需要灵活性的关键部分中非常重要。

1. 函数中的泛型类型

泛型编程通常应用于函数中以避免重复。比如说,有一个函数可以接受字符串或数字作为参数。

    function identity(value: any): any {
      return value;
    }
    // 定义一个返回参数本身的函数 identity
    const result1 = identity(42); // result1: 任何类型
    const result2 = identity("hello"); // result2: 任何类型

进入全屏模式。退出全屏模式。

这个功能运行得很好。但它使用了任意类型,这意味着Typescript无法追踪具体的类型。因此,返回值被标记为any类型,Typescript也无法再确保类型安全。如果我们想保持类型安全,我们就得写两个不同的函数,一个返回字符串的,另一个返回数字的。然而,这样做会增加代码的重复。

我们可以通过使用泛型来改进上面的功能,从而保留类型信息。

函数 identity<T>(value: 类型): T {
  return value;
}
const result1 = identity<数字>(42); // result1: 数字
const result2 = identity<字符串>("hello"); // result2: 字符串

点击全屏模式;点击退出全屏

T 表示该方法使用的类型。如果存在 TTypescript 会验证输入类型和返回类型是否一致。

另外,我们也可以不明确指定参数类型来定义函数的形式。

const result3 = identity(100); // result3: 数字
const result4 = identity("world"); // result4: 字符串

切换到全屏 / 退出全屏

在 TypeScript 中,你可以为一个函数或组件指定多种类型。可以使用多个泛型类型参数来处理这些类型。例如,你可能希望创建一个接受两种不同类型输入并返回它们作为一对的函数。

    function multipleParams<T, U>(first: T, second: U): [T, U] {
     return [first, second];
    }
    const result1 = multipleParams<string, number>("hello", 42); // 结果1: 类型为 [string, number]
    const result2 = multipleParams<string, number>("hello", "world"); // 结果2: 会抛出类型错误

进入全屏模式,退出全屏

在这种情形下,该函数返回一个元组,第一个元素的类型为T,第二个元素的类型为U,这使得函数可以安全地处理两种不同的类型。

2. 在 TypeScript 中的默认类型(Default Types)

Typescript 中,你可以为泛型提供一个默认类型参数,如果不指定类型,Typescript 就会使用这个默认设置。

    function createArray<T = string>(length: number, value: T): T[] {
     return Array(length).fill(value);
    }

    const stringArray = createArray(3, "hello"); // T 默认是 string,所以 stringArray 就是一个字符串数组
    const numberArray = createArray<number>(3, 42); // T 明确设置为 number,所以 numberArray 就是一个数字数组

全屏显示。退出全屏。

在这个例子中,类型参数 T 默认为字符串类型。如果开发人员在调用函数时没有指定类型,T 将自动设为字符串。

3. 通用接口规范

Typescript 泛型也可以应用于接口。比如说,定义一个Box接口为例,其值类型不限。

    interface Box {
      value: any;
    }
    const numberBox: Box = { value: 123 }; // 正确 // 这是正确的实现
    const stringBox: Box = { value: "hello" }; // 正确 // 这是正确的实现

全屏预览。退出预览。

这更像一个通用函数的例子;由于我们没有定义特定的类型,这段代码运行也不会有问题。但是,由于值被定义为any类型,我们可能会遇到一些与类型相关的错误。

通过定义一个泛型接口,我们可以在下面确保类型安全。

    interface Box<Type> {
      value: Type;
    }
    const numberBox: Box<number> = { value: 123 }; // 数字类型
    const stringBox: Box<string> = { value: "hello" }; // 字符串类型
    const stringBox2: Box<string> = { value: 123 }; // 错误:类型不匹配

切换到全屏模式,结束全屏模式

界面是通用的,且其值类型必须是 Type 变量。在创建实例时,可以将 Type 变量设置为数字或字符串类型,这样 TypeScript 就能确保类型的一致性。

4. 泛型类

我们也可以用泛型来编写类,以处理不同类型的值,同时保持类型的安全性。让我们创建一个可以存储和检索任何类型的值的Storage类。

    class 存储类 {
      private 数据: any = undefined;
      设置项(项: any) {
        this.数据 = 项;
      }
      获取项(): any {
        return this.数据;
      }
    }
    const 存储实例 = new 存储类();
    存储实例.setItem(123);
    const 项 = 存储实例.getItem();

切换到全屏 关闭全屏

这个类可以运行,因为数据类型是 anygetItem 方法返回 any,这使得类型安全性丢失。因此,我们可以用泛型重写这个类来提高类型安全性。

class Storage<T> {
  private data: T;
  setItem(item: T): void {
    this.data = item;
  }
  getItem(): T {
    return this.data;
  }
}
// 泛型T表示存储的数据类型。
const numberStorage = new Storage<number>();
// 以下代码定义了一个可以储存任意类型值的Storage类,并创建了一个用于存储数字的实例。
numberStorage.setItem(123);
const item = numberStorage.getItem();
// 从Storage实例中获取存储的值。

切换到全屏模式,恢复常规模式

在这种情况下,类型 TStorage 类使用。在定义类型和创建实例时,TypeScript 会确保数据的正确性。当你定义类型并创建实例的时候,TypeScript 就会确保数据的正确性。在这个代码示例中,getItem 方法将返回一个数值。

5. 通用约束条件:

你可以用泛型约束来限制泛型可以接受的类型,确保它们具备特定特性。

例如,如果你有一个需要访问输入的 length 属性的函数,你可以使用类型约束来确保只有具有 length 属性的类型才被允许。这样可以防止 Typescript 报错或让不兼容的类型通过。

    function printLength<T>(value: T): void {
      console.log(value.length); // 错误:Typescript 不知道 value 是否具有长度。
     } 

进入全屏, 退出全屏

在这里,T 对象没有定义 length 属性。为了绕过这个问题,我们可以加入一个约束条件,指定 T 必须有 length 属性。我们可以通过 T extends { length: number } 的方式来实现这一点。

    function printLength<T extends { length: number}>(value: T): void {
      console.log(value.length); // 现在 TypeScript 识别了 length 属性
    }

    printLength("hello"); // 输出:5
    printLength([1, 2, 3]); // 输出:3
    printLength({ length: 10 }); // 输出:10

全屏模式,退出全屏,

现在,这个函数有了一个长度属性;它不会出错,并且会根据输入长度正常运行。

总结

Typescript 泛型允许你编写灵活、可重用且类型安全的代码。你可以使用这些泛型类、方法和接口来管理多种数据类型,无需重复代码。本文探讨了几个关键用例,比如泛型约束、多种类型和默认类型,并展示了它们如何让程序更易于扩展和维护。

了解 TypeScript 泛型能帮助你编写更精确、灵活且类型安全的代码,使你的 TypeScript 应用更健壮。

更多相关博客

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消