【TS】九天学会TS语法——6.TypeScript泛型图文详解

???? 欢迎光临清清ww的博客小天地????

???? 个人主页:【清清ww】????

???? 系列专栏:vue3 | TypeScript ????

???? 学习本无底,前进莫徬徨。????

 

开始学习!

目录

 引言

一.什么是泛型

二.泛型的基本使用

1.泛型函数

2.泛型类

3.泛型接口

三.泛型的优点

四.泛型的进阶使用

1.泛型约束

2. 多个类型参数

 引言

有时候,我们会遇到这样的情况:对不同的数据类型需要执行相同的操作逻辑。而泛型,能让我们的代码能够以统一的方式处理多样化的数据类型。这就是泛型的强大之处。


一.什么是泛型

泛型就是“通用类型”的意思,它是一种编程语言特性,允许在定义函数、类或接口时,不预先指定具体的类型,而是使用一个占位符(通常用字母 T、U 等表示)来表示类型。这样我们就可以在运行代码之前不指定具体的数据类型,而是在使用的时候再决定,从而使得代码能够更加灵活地处理不同类型的数据。

泛型的语法是这样的:

function 函数名<T>(参数: T):T {
    // ...
}

class 类名<T> {
    // ...
}

interface 接口名<T> {
    // ...
}

这里的" T " 叫泛型参数除了"T"外,泛型参数还可以用" U "、" K "、" V "、" E "等单个大写字母表示,它们有一些约定俗成的规律:

  • T 通常代表 “Type”

  • U  V 可以代表 “Type” 的其他变体

  • K 通常代表 “Key”

  • V 通常代表 “Value”

  • E 通常代表 “Element”


二.泛型的基本使用

泛型不仅使我们创建能够处理多种数据类型的函数,而且还允许我们定义可以适应不同数据类型的接口。下面,我们将分别探讨如何使用泛型来定义函数、类和接口。

1.泛型函数

可以处理多种数据类型的函数。

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

泛型函数就像一个通用的工具,它可以用来处理不同类型的数据,而不需要为每种类型写一个单独的函数。

????????举个例子????????

假设我们需要这样一个函数,它的作用是返回我们传给它的任何东西。没有泛型,就需要为不同类型写不同的函数,比如:

function returnNumber(num) {
    return num;
}

function returnString(str) {
    return str;
}

使用泛型,就可以写一个函数来处理任何类型:

function returnAnything<T>(thing: T): T {
    return thing;
}

在这个例子中,<T>是一个占位符,它表示任何类型。当函数被调用时,你可以传递任何类型的数据,比如:

let myNumber = returnAnything(5);  // myNumber 是数字类型
let myString = returnAnything("Hello");  // myString 是字符串类型

2.泛型类

可以处理多种类型的类。

class GenericClass<T> {
    property: T;
    constructor(value: T) {
        this.property = value;
    }
}

泛型类就像一个模具,可以用它来制作不同类型的产品。

????????举个例子????????

假设我们想创建一个简单的盒子类,它可以存储任何类型的数据。没有泛型,就需要为每种类型创建一个类,比如:

class NumberBox {
    private content: number;
    constructor(value: number) {
        this.content = value;
    }
}

class StringBox {
    private content: string;
    constructor(value: string) {
        this.content = value;
    }
}

使用泛型,只用创建一个通用的盒子类:

class Box<T> {
    private content: T;
    constructor(value: T) {
        this.content = value;
    }
    getContent(): T {
        return this.content;
    }
}

现在,我们可以用这个类来创建任何类型的盒子:

let numberBox = new Box<number>(5);
let stringBox = new Box<string>("Hello");

3.泛型接口

定义一个具有泛型属性的接口。

interface GenericInterface<T> {
    (arg: T): T;
}

泛型接口就像一个蓝图,它定义了一个可以应用于多种类型的结构。

????????举个例子????????

假设我们需要一个函数,它接受一个参数并返回相同类型的值。没有泛型,需要为每种类型定义一个接口,比如:

interface NumberFunction {
    (arg: number): number;
}

interface StringFunction {
    (arg: string): string;
}

使用泛型,就定义一个通用的接口:

interface GenericFunction<T> {
    (arg: T): T;
}

现在,我们可以用这个接口来描述任何类型的函数:

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

let myNumberFunction: GenericFunction<number> = identity;
let myStringFunction: GenericFunction<string> = identity;

在这个例子中,identity函数实现了GenericFunction接口,并且可以用于处理任何类型的数据。


三.泛型的优点

泛型的优点简要来说就两点:类型安全、代码复用。

  • 类型安全:泛型可以在编译时检查数据类型,确保数据类型的正确性,减少运行时错误。
  • 代码复用:不需要为每种类型编写多个版本的函数或类。


四.泛型的进阶使用

1.泛型约束

可以对接受的类型进行限制,只接受具有特定属性的对象。

interface Lengthwise {
    length: number;
}
function logLength<T extends Lengthwise>(arg: T) {
    console.log(arg.length);
}

泛型约束就像是给泛型加了一个“过滤器”,只允许符合某些条件的类型通过。比如,如果我们需要对输入的数据做一些操作,但这些操作只对具有某些特征的数据有意义,就可以使用泛型约束,确保只有符合这些特征的数据类型可以被使用。

????????举个例子????????

有这样一个函数,它的作用是打印出任何可以度量的东西的长度,要求这些数据类型必须有一个length属性。

interface HasLength { length: number; }

function printLength(thing: T) { console.log("The length is: " + thing.length); }

// 使用例子 printLength(“Hello”); // 正确,字符串有length属性 printLength([1, 2, 3]); // 正确,数组有length属性

// 错误的例子,数字没有length属性 // printLength(100); // 这会报错

HasLength接口定义了一个约束,即任何使用这个约束的类型都必须有一个length属性。printLength函数使用了这个约束,所以它只能接受有length属性的数据。

2. 多个类型参数

泛型可以接受多个类型参数,用逗号分隔。

function swap<T, U>(tuple: [T, U]): [U, T] {
    return [tuple[1], tuple[0]];
}

多个类型参数就像是给泛型函数提供了多个“插槽”,每个插槽可以放不同类型的数据。这样,你就可以创建更灵活的函数,它们可以同时处理多种不同类型的数据。

????????举个例子????????

假设我们正在开发一个数据处理器,它需要能够接受不同类型的数据输入,并对这些数据进行特定的处理。我们可以使用多个类型参数来定义一个泛型函数,使其能够同时处理数值和字符串类型的数据。

// 定义一个泛型函数,它接受数值和字符串两种类型的数据
function processData<T extends number, U extends string>(numData: T, strData: U): [T, U] {
    // 对数值数据进行加法处理
    const processedNum = numData + 10;
    // 对字符串数据进行拼接处理
    const processedStr = strData + " processed";
    
    return [processedNum, processedStr];
}

// 使用例子
let result = processData<Number, String>(25, "Hello");  // 返回: [35, "Hello processed"]

processData 函数接受两个类型参数 T 和 UT 被约束为数值类型,而 U 被约束为字符串类型。这个函数能够接受一个数值和一个字符串作为输入,分别对它们进行处理,并返回一个包含处理后的数值和字符串的元组。

这样就实现了只创建了一个函数,但能够同时处理多种不同类型数据,可谓十分灵活。


????感谢您的细心品读,完成了这篇关于【TS】九天学会TS语法—— 6.TS泛型图文详解 的旅程。 ????

???? 您的每一个鼓励都是我不断更新的动力,不要忘记点赞收藏????

???? 期待与您一同深入前端技术的海洋,共同探索那些未知的宝藏,揭开Web开发的层层迷雾。????

???? ???? 感恩您的支持与同行,愿我们的前端征途越走越远!???? ????

上一篇:基于SpringBoot的Java教学支持系统开发指南


下一篇:靠谷歌广告赚了100美刀,程序员可以照这个思路去干