TypeScript中的泛型(泛型函数、接口、类、泛型约束)

2023-11-07

一、泛型函数

TypeScript泛型是一种可以使代码具有更高的可重用性和泛化能力的特性。通过泛型,我们可以定义一种通用的类型或函数,使其能够应对多种类型的输入。泛型在类、函数、接口等多种场景下都可以使用。

具体来说,在定义泛型函数时,我们可以使用来表示一个类型变量,这样我们就可以在函数中使用这个泛型类型来作为参数类型、返回值类型或变量类型等。例如:

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

let myIdentity: <T>(arg: T) => T = echo;

在这个例子中,我们定义了一个echo函数,它使用泛型类型变量T作为输入参数类型和返回值类型,这样我们就可以使用不同类型的参数来调用该函数,例如:

console.log(echo('Hello TypeScript!')); // 输出:Hello TypeScript!
console.log(echo(123)); // 输出:123

二、泛型类

在类的定义中使用泛型,也可以大大提高代码的复用性和灵活性。例如下面的代码:

class Stack<T> {
    private items: T[] = [];

    push(item: T) {
        this.items.push(item);
    }

    pop(): T {
        return this.items.pop();
    }
}

let strStack = new Stack<string>();
strStack.push('apple');
strStack.push('banana');
strStack.push('cherry');

console.log(strStack.pop());
console.log(strStack.pop());
console.log(strStack.pop());

在上面的代码中,定义了一个Stack类,并声明了泛型类型T,用于在push和pop方法中进行类型的转换。通过传入不同类型的参数,可以得到不同类型的Stack实例。

三、泛型接口

interface Map<K, V> {
    set(key: K, val: V): void;
    get(key: K): V | undefined;
    has(key: K): boolean;
    clear(): void;
}

let numMap: Map<number, string> = {
    set(key: number, val: string) {
        // 添加键值对
    },
    get(key: number): string | undefined {
        // 获取键值对
    },
    has(key: number): boolean {
        // 判断是否存在
    },
    clear() {
        // 清空Map
    }
};

numMap.set(1, 'apple');
numMap.set(2, 'banana');

console.log(numMap.get(1));
console.log(numMap.get(2));

在上面的代码中,定义了一个Map接口,并使用泛型K和V来约束键和值的类型。通过传入不同类型的参数,可以得到不同类型的Map实例,并实现对不同类型键值对的操作。

四、泛型约束、泛型限制用法<T> extends {属性:类型}

在 TypeScript 中,泛型约束是一种让泛型类型参数只能取某些特定类型的值的机制。这个特定类型的限制可以是一个接口、类、枚举或其他类型。

例如,假设我们有一个泛型函数,它接受一个类型参数 T 和一个对象参数 obj,这个函数返回 obj 中的第一个 T 类型的属性值:

function getPropertyValue<T>(obj: object): T {
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      let value = obj[key];
      if (value instanceof T) {
        return value;
      }
    }
  }
  throw new Error(`No property of type ${T.name} found.`);
}

但是,这个函数可能会遇到一些问题。例如,如果我们调用 getPropertyValue({ a: ‘1’, b: 2, c: 3 }),那么会抛出一个错误,因为字符串 ‘1’ 不是一个 number 类型。

为了解决这个问题,我们可以使用泛型约束来限制 T 只能取某些特定类型的值。例如,我们可以要求 T 必须是实现了 Number 接口的类型:

interface Number {
  new (value?: any): number;
  (value?: any): number;
  readonly NaN: number;
  readonly MAX_VALUE: number;
  readonly MIN_VALUE: number;
  readonly NEGATIVE_INFINITY: number;
  readonly POSITIVE_INFINITY: number;
}

function getPropertyValue<T extends Number>(obj: object): T {
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      let value = obj[key];
      if (value instanceof T) {
        return value;
      }
    }
  }
  throw new Error(`No property of type ${T.name} found.`);
}

现在,如果我们调用 getPropertyValue({ a: ‘1’, b: 2, c: 3 }),就会得到一个类型错误,因为 ‘1’ 不是一个实现了 Number 接口的类型。但是,如果我们调用 getPropertyValue({ a: 1, b: 2, c: 3 }),就能得到正确的结果了。

另一泛型约束\<key extends keyof Type>

在 TypeScript 中,<key extends keyof Type> 是一种泛型约束方式,用于限制一个泛型类型参数 key 的范围。

其中,keyof 关键字可以用于获取一个类型 Type 的所有属性名,返回一个字符串字面量类型,例如:

interface Person {
  name: string;
  age: number;
}

type PersonKeys = keyof Person; // "name" | "age"

<key extends keyof Type> 中,extends 关键字表示限制 key 的取值只能是 Type 类型中已有的属性名。也就是说,只有 key 取值为 Type 类型中已有的属性名才符合类型约束,例如:

function getValueByKey<T extends object, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const person = {
  name: 'Bob',
  age: 25,
};
const name = getValueByKey(person, 'name'); // name 的类型是 string
const age = getValueByKey(person, 'age'); // age 的类型是 number
const gender = getValueByKey(person, 'gender'); // 编译报错,gender 不是 person 中的属性

在上面的例子中,getValueByKey 函数接收两个参数:一个泛型类型参数 T,代表输入对象的类型;一个泛型类型参数 K,代表属性名的类型。

extends keyof T 约束了类型参数 K 必须是输入对象类型 T 中已存在的属性名。因此,调用 getValueByKey 函数传入一个不存在的属性名 gender 会引发编译错误。

五、使用泛型注意点

在编写泛型方法时,应该注意以下几点:

  1. 泛型形参的名称应该描述清楚其作用和范围,尽量不要使用单个字母的形参名称;
  2. 在使用泛型类型的属性或方法时,应该确保该属性或方法在所有可能的泛型类型中都是存在的,不要使用不存在的属性或方法;
  3. 在使用泛型类型的操作符时,应该考虑不同类型之间可能的差异性和兼容性问题,避免出现类型错误
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TypeScript中的泛型(泛型函数、接口、类、泛型约束) 的相关文章

  • 取消html5浏览器中的单图请求

    我正在动态加载 大 图像以绘制到 html5 画布中 如下所示 var t new Image t onload t src http myurl 但每隔一段时间就会想取消图片请求完全地 我想出的唯一方法是设置src to i e t sr
  • HTML/VBA Click 事件未触发

    这是我第一次在 StackOverflow 上发布问题 到目前为止 我已经能够通过 VBA 帮助论坛解决我的大部分问题 我的问题很简单 我有一个自动数据拉取 我需要在其中导出数据 我过去曾在这方面取得过成功 但这次略有不同 我尝试单击以生成
  • TypeScript 编译速度极慢 > 12 秒

    只是把它放在那里看看其他人是否也遇到这个问题 我已经使用 webpack 作为我的构建工具 使用 typescript 构建了一个 Angular 2 应用程序 一切都运行良好 但是我注意到 typescript 编译超级超级慢 我现在只有
  • VBA / HTML / jQuery 选择自动完成 - 在列表中选择

    我正在尝试使用 Excel 中的 VBA 在网站的列表中选择一个值 这不是一个 正常列表 该网站使用 jQuery 选择自动完成 如下所示 example http davidwalsh name demo jquery chosen ph
  • 在网页上的文本框中键入内容时删除所有空格

    我如何在用户打字时即时删除输入到文本框中的空格 function var txt myTextbox var func function txt val txt val replace s g txt keyup func blur fun
  • jQuery 选择 # id 以单词为前缀,计数器为后缀

    有没有办法用 jQuery 选择所有带有前缀 my 和后缀 0 9 的 id 像这样的 my 1 4 还是可以用循环来实现 div div div div div div div div div div 第一个想法 似乎效果很好 div i
  • 如何使用canvas.toDataURL()将画布保存为图像?

    我目前正在构建一个 HTML5 Web 应用程序 Phonegap 本机应用程序 我似乎不知道如何将画布保存为图像canvas toDataURL 有人可以帮我吗 这是代码 有什么问题吗 我的画布被命名为 canvasSignature J
  • 使用 CryptoJS 更改密钥 [重复]

    这个问题在这里已经有答案了 我正在使用 CryptoJS 来加密和解密文本 在这里 我只是获取消息并显示加密和解密消息 我使用DES算法进行加密和解密 这是我的 HTML 文件
  • 是否可以使用 javascript 测试用户的浏览器/操作系统是否支持给定类型的链接?

    是否可以使用 javascript 或其他任何东西 测试用户的操作系统 浏览器是否支持给定的 url 方案 例如 大多数仅使用网络邮件的用户计算机上未设置 mailto 是否有可能以某种方式捕获单击 mailto 链接的尝试并弹出比浏览器错
  • 仅一页 JavaScript 应用程序

    您是否尝试过单页 Web 应用程序 即浏览器仅从服务器 获取 一页 其余部分由客户端 JavaScript 代码处理 此类 应用程序页面 的一个很好的例子是 Gmail 对于更简单的应用程序 例如博客和 CMS 使用这种方法有哪些优点和缺点
  • 在为 RXJS 可观察量编写测试时,如何避免让调度程序通过我的业务逻辑?

    我发现使某些测试通过的唯一方法是显式地将调度程序传递给函数 为了便于说明 请考虑以下函数 function doStuff stream return stream delay 100 filter x gt x 2 0 map x gt
  • 如何在 Angular 4 项目中使用 ActiveXObject

    我正在尝试使用 ActiveXObject 如下所示 getActiveXObject pdfCtrl return new ActiveXObject pdfCtrl checkPDF let plugin null if this ge
  • Javascript - 将值从下拉框传递到 Google Maps API

    我正在使用 Google 地图 API 为一家出租车公司创建报价表 目前 用户在 2 个文本框中输入出发点和接载点 API 会计算两点之间的距离以及行程费用 我正在尝试添加两个具有设定位置的下拉框 以便用户可以选择这些位置之一或使用文本框输
  • 如何流式传输 OpenAI 的完成 API?

    我想流式传输结果通过 OpenAI 的 API 完成 https beta openai com docs api reference completions 该文档提到使用服务器发送的事件 https developer mozilla
  • 是否有任何非轮询方式来检测 DOM 元素的大小或位置何时发生变化?

    很长一段时间以来 我一直在寻找一种方法来检测 DOM 元素的大小或位置何时发生变化 这可能是因为窗口调整了大小 或者因为向该元素添加了新的子元素 或者因为在该元素周围添加了新元素 或者因为 CSS 规则已更改 或者因为用户更改了浏览器的字体
  • 在d3.js中将2D形状转换为3D,并根据ANGULAR中的值调整高度

    我正在使用 d3 js v6 创建以下 2D 图表表示的 3D 图表 这个圆圈中有多个正方形 每个正方形都根据值分配了一种颜色 值越大 正方形越暗 现在我想将其转换为 3D 形状 其中当值变高时 只有特定正方形的高度会增加 因此结果在某种程
  • 如何使JavaScript函数在Eclipse“大纲视图”中可见?

    我有这样的代码 但如果它在匿名函数中定义 则无法打开函数大纲 类没有问题 我该如何概述something2 请分享一些提示 我可以将所有函数标记为构造函数 但这是无效的方法 start of track event required deb
  • 将 javascript 整数转换为字节数组并返回

    function intFromBytes x var val 0 for var i 0 i lt x length i val x i if i lt x length 1 val val lt lt 8 return val func
  • Chartjs刻度标签位置

    尝试让 Y 轴刻度标签看起来像image https i stack imgur com XgoxX png 位于秤顶部且不旋转 缩放选项当前如下所示 scales yAxes id temp scaleLabel display true
  • JavaScript 代码在不使用 ActiveX 的情况下截取网站屏幕截图

    我有一个用户与之交互的 JavaScript 应用程序 我需要保存当前界面的外观 裁剪出我需要的部分 或者通过指定div只拍摄我需要的部分 然后发送回服务器 显然任何外部服务都无法做到这一点 我需要一个 JavaScript 或Flash

随机推荐

  • Android启动模式

    其中MainActivity是所有操作的第一个Activity 1 A为standard B为singleInstance C为standard A B C 由下面的结果可知 B会单独创建一个任务站 且里面只能有他一个任务 即使是他启动的A
  • maven pom文件详解

  • 记一次sql优化经历(优化in语句)

    业务背景 根据客户群组查询标签 群组和标签的对应关系在tb biz type tags中 根据标签查询客户的手机号和机构标识 tb customer tags 根据手机号和机构标识 筛选出符合要求的客户信息 tb account 已知 客户
  • 加列法计算lower unit matrix inversion

    include
  • vscode配置文件在哪?

    在这里 看图 文件file 首选项 设置 点那个图标
  • 【C++】STL-函数对象 + 谓词

    1 函数对象使用 include
  • 在 window 上安装GPU版本的torch

    pip install https download pytorch org whl cu80 torch 1 0 0 cp37 cp37m win amd64 whl i https pypi tuna tsinghua edu cn s
  • fdisk 命令实现磁盘分区详细教程

    目录 分区步骤 1 添加新的磁盘 2 查看新的磁盘 3 使用fdisk命令分区 4 重新读取分区表信息 5 格式化分区 6 建立挂载点并挂载 总结 fdisk命令来自于英文词组 Partition table manipulator for
  • 华为OD机考20220622

    考试时间 2022 06 22 总分 136分 第一题 字符串分割 水仙花数 用例通过率 11 1 第二题 内存资源分配 用例通过率 95 8 第三题 模拟内存分配 用例通过率 15 之前在网上也看了很多分享 虽然机考没通过 不过也分享一下
  • CentOS 安装opencv3.4.12教程,一次编译通过,避免踩坑

    1 下载和安装 在官方网址 Home OpenCV 下载该3 x版本的opencv和opencv contrib的zip源码文件 本文以opencv3 4 12为例 然后解压该zip文件 即得到 unzip opencv 3 4 12 zi
  • 回调函数详解

    一 什么是回调函数 回调函数是指 使用者自己定义一个函数 实现这个函数的程序内容 然后把这个函数 入口地址 作为参数传入别人 或系统 的函数中 由别人 或系统 的函数在运行时来调用的函数 函数是你实现的 但由别人 或系统 的函数在运行时通过
  • 使用Glide对网络图片进行圆形和圆角的处理

    在开发中欧经常会遇见对图片的圆形和圆角的处理 头像一般圆形较多 之前使用的还是Volley ImageLoader来进行的加载网络图片 当时遇见这个需求找了许多资料 后来朋友一致推荐我将Volley ImageLoader换成Glide 不
  • 计算机毕设之基于SSM框架仓库管理系统

    1 简介 博主介绍 全网粉丝30W csdn特邀作者 博客专家 CSDN新星计划导师 编程领域优质创作者 博客之星 各平台优质作者 专注于Java python等技术领域和毕业项目实战 文末获取源码联系 计算机毕设之基于SSM框架仓库管理系
  • chatgpt赋能python:Python如何实现中文SEO的优化

    Python如何实现中文SEO的优化 伴随着互联网的发展 中文网站数量不断增多 而如何让中文网站在搜索引擎中更好的展现 就成为了一个很热门的问题 SEO 搜索引擎优化 是实现网站流量增长甚至盈利的关键 在这里 我们将介绍如何使用Python
  • VC++ 在任务栏图标上显示进度条效果

    该功能主要是通过COM接口ITaskbarList3 来实现进度效果显示功能 头文件定义 CSWTaskBarList h pragma once include
  • Android bundetool 详解

    android bundetool 详解 一 什么是 bundetool 为什么要使用 bundetool 在使用Android Studio 构建 Android App Bundle 后 需要测试 Android App Bundle
  • css设置背景图片大小_如何使用CSS设置背景图片大小?

    css设置背景图片大小 Introduction 介绍 As we all know that the images are a very responsive yet very creative way to display your w
  • WIN10去除磁盘写保护(只读属性)的步骤

    WIN10去除磁盘写保护 只读属性 的步骤 1 使用管理员权限进入win10的命令模式 使用系统搜索cmd 然后使用管理员模式打开 如下图 点击搜索 2 输入cmd 3 使用鼠标点击使用管理员身份打开 4 打开之后切换到C盘根目录 cd 这
  • 信号完整性分析基础知识之有损传输线、上升时间衰减和材料特性(一):为什么要关注损耗?

    一个具有极快上升沿的信号输入到真实传输线中 在从传输线输出的时候上升时间会很长 例如 一个上升时间为50ps的信号 在经过一段36inch长 50Ohm传输线后 上升时间增加到1ns 上升时间的退化是由于传输线的损耗 这也是引起码间干扰 i
  • TypeScript中的泛型(泛型函数、接口、类、泛型约束)

    一 泛型函数 TypeScript泛型是一种可以使代码具有更高的可重用性和泛化能力的特性 通过泛型 我们可以定义一种通用的类型或函数 使其能够应对多种类型的输入 泛型在类 函数 接口等多种场景下都可以使用 具体来说 在定义泛型函数时 我们可