TypeScript 装饰器都有那些应用场景?如何更快的上手?
TypeScript 装饰器简介
在 TypeScript 中,装饰器(Decorators)是一种特殊的语法,用于在类、类方法、属性、访问器等上动态地添加行为或修改现有行为。装饰器可以用来增强类的功能、修改方法的行为,或者修改类的元数据等。它们通常用于元编程和 AOP(面向切面编程)等场景。
装饰器在 TypeScript 中的实现基于 ECMAScript 提案的实验性特性,但目前 TypeScript 已经支持了装饰器的编写和使用。需要注意的是,装饰器特性必须通过 experimentalDecorators 编译选项开启。
开启装饰器支持
在 tsconfig.json 中配置:
{"compilerOptions": {"experimentalDecorators": true}
}
装饰器的类型
装饰器可以应用于以下几种目标:
- 类装饰器 (Class Decorators):应用于类构造函数,修改类的行为或元数据。
- 方法装饰器 (Method Decorators):应用于类的方法,允许修改方法的属性或行为。
- 属性装饰器 (Property Decorators):应用于类的属性,用于修改或定义属性的元数据。
- 访问器装饰器 (Accessor Decorators):应用于类的 getter 或 setter 方法。
- 参数装饰器 (Parameter Decorators):应用于方法参数,主要用于修改或注入方法参数的元数据。
装饰器的应用场景
装饰器常用于以下几个场景:
- 类的功能增强:如注入依赖、日志记录、权限校验等。
- 方法行为修改:例如,控制方法的执行、缓存机制、性能监控等。
- 自动化注入:在一些框架中,装饰器用来自动注入依赖,比如 Angular 中的服务注入。
- 性能分析和日志:自动记录函数的调用时间、参数等。
示例:使用装饰器的实际场景
假设我们有一个项目需要记录方法调用的日志,并且需要验证用户是否有权限执行某些操作。我们可以使用装饰器来实现这些功能。
1. 类装饰器
类装饰器通常用于增强类的行为,比如记录日志、依赖注入等。
function Logger(constructor: Function) {console.log(`Class ${constructor.name} is instantiated.`);
}@Logger
class UserService {constructor() {console.log("UserService instance created.");}
}const userService = new UserService();
解释:Logger 装饰器会在类实例化时打印出该类的名称。在 @Logger 之后,当 UserService 被实例化时,控制台输出 Class UserService is instantiated.。
2. 方法装饰器
方法装饰器可以修改方法的行为或添加额外的功能。我们可以使用方法装饰器来记录日志,验证权限等。
function Log(target: any, propertyName: string, descriptor: PropertyDescriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {console.log(`Method ${propertyName} is called with args: ${args}`);return originalMethod.apply(this, args);};
}class UserService {@LoggetUser(userId: number) {console.log(`Fetching user with ID: ${userId}`);}
}const userService = new UserService();
userService.getUser(42);
解释:@Log 装饰器会修改 getUser 方法,在调用该方法时记录日志,打印出方法名和传入的参数。输出结果为:
Method getUser is called with args: [42]
Fetching user with ID: 42
3. 属性装饰器
属性装饰器可以用来修改类的属性行为或元数据。例如,我们可以用它来设置字段的可访问性或记录日志。
function Observable(target: any, propertyName: string) {let value = target[propertyName];const getter = () => {console.log(`Getting value of ${propertyName}: ${value}`);return value;};const setter = (newVal: any) => {console.log(`Setting value of ${propertyName} to: ${newVal}`);value = newVal;};Object.defineProperty(target, propertyName, {get: getter,set: setter,});
}class User {@Observablename: string;constructor(name: string) {this.name = name;}
}const user = new User("Alice");
user.name = "Bob"; // Console logs: Setting value of name to: Bob
console.log(user.name); // Console logs: Getting value of name: Bob
解释:@Observable 装饰器为 name 属性创建了 getter 和 setter 方法,控制属性的访问并记录相关日志。
4. 权限校验的实际应用
装饰器常用于权限校验等场景,检查用户是否有权限执行某个方法。例如:
function PermissionRequired(permission: string) {return function (target: any, propertyName: string, descriptor: PropertyDescriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {const userPermissions = ["READ", "WRITE"]; // 假设的用户权限if (!userPermissions.includes(permission)) {console.log(`Permission denied. Missing permission: ${permission}`);return;}return originalMethod.apply(this, args);};};
}class DocumentService {@PermissionRequired("WRITE")editDocument() {console.log("Document is being edited.");}
}const documentService = new DocumentService();
documentService.editDocument(); // 如果权限包含 "WRITE",则输出 "Document is being edited."
解释:@PermissionRequired 装饰器会在方法执行前检查当前用户的权限。如果权限不足,则拒绝执行方法。
组合使用装饰器
在实际项目中,装饰器可以进行组合使用,进行多种功能的扩展。例如,我们可以结合使用日志记录和权限校验装饰器:
function Log(target: any, propertyName: string, descriptor: PropertyDescriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {console.log(`Calling method ${propertyName} with arguments: ${args}`);return originalMethod.apply(this, args);};
}function PermissionRequired(permission: string) {return function (target: any, propertyName: string, descriptor: PropertyDescriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {const userPermissions = ["READ", "WRITE"];if (!userPermissions.includes(permission)) {console.log(`Permission denied. Missing permission: ${permission}`);return;}return originalMethod.apply(this, args);};};
}class FileService {@Log@PermissionRequired("READ")readFile(filePath: string) {console.log(`Reading file from ${filePath}`);}
}const fileService = new FileService();
fileService.readFile("/path/to/file");
解释:此时,readFile 方法同时拥有日志记录和权限校验的功能,先打印调用日志,再检查权限。
总结
TypeScript 装饰器是一种强大的工具,可以在类、方法、属性、参数等地方进行功能扩展,常用于日志记录、权限校验、性能监控等场景。在实际开发中,装饰器的应用通常能大大减少冗余代码、提高代码的可维护性和灵活性。通过装饰器,开发者可以以声明式的方式对类和方法进行增强,并实现高层次的抽象和代码重用。
常见应用场景:
- 日志记录
- 性能监控
- 权限校验
- 依赖注入
- 数据验证
- 缓存机制
理解装饰器及其应用方式,可以让你在开发中更加得心应手,特别是当代码规模增大时,装饰器能够帮助你以更简洁的方式处理复杂的逻辑。
相关文章:
TypeScript 装饰器都有那些应用场景?如何更快的上手?
TypeScript 装饰器简介 在 TypeScript 中,装饰器(Decorators)是一种特殊的语法,用于在类、类方法、属性、访问器等上动态地添加行为或修改现有行为。装饰器可以用来增强类的功能、修改方法的行为,或者修改类的元数据等…...
堆优化版本的Prim
prim和dijkstra每轮找最小边的松弛操作其实是同源的,因而受dijkstra堆优化的启发,那么prim也可以采用小根堆进行优化。时间复杂度也由 O ( n 2 ) O(n^2) O(n2)降为 O ( n l o g n ) O(nlogn) O(nlogn)。 测试一下吧:原题链接 #include <i…...
Ubuntu上安装MySQL并且实现远程登录
目录 下载网络工具 查看网络连接 更新系统软件包; 安装mysql数据库 查看mysql数据库状态 以数字ip形式显示mysql的监听状态。(默认监听端口是3306) 查看安装mysql数据库时系统创建的目录信息。 根据查询到的系统用户名以及随机密码&a…...
蓝桥杯每日真题 - 第21天
题目:(空间) 题目描述(12届 C&C B组A题) 解题思路: 转换单位: 内存总大小为 256MB,换算为字节: 25610241024268,435,456字节 计算每个整数占用空间: 每个 32 位整数占用…...
(长期更新)《零基础入门 ArcGIS(ArcMap) 》实验一(下)----空间数据的编辑与处理(超超超详细!!!)
续上篇博客(长期更新)《零基础入门 ArcGIS(ArcMap) 》实验一(上)----空间数据的编辑与处理(超超超详细!!!)-CSDN博客 继续更新 目录 什么是拓扑? 1.3.5道路…...
NLP论文速读(CVPR 2024)|使用DPO进行diffusion模型对齐
论文速读|Diffusion Model Alignment Using Direct Preference Optimization 论文信息: 简介: 本文探讨的背景是大型语言模型(LLMs)通过人类比较数据和从人类反馈中学习(RLHF)的方法进行微调,以…...
操作系统——揭开盖子
计算机执行时——取指执行 es:bx等于从0x9000开始,到0x90200结束...
如何在 React 项目中应用 TypeScript?应该注意那些点?结合实际项目示例及代码进行讲解!
在 React 项目中应用 TypeScript 是提升开发效率、增强代码可维护性和可读性的好方法。TypeScript 提供了静态类型检查、自动补全和代码提示等功能,这对于 React 开发者来说,能够帮助早期发现潜在的 bug,提高开发体验。 1. 项目初始化 在现…...
C++学习第四天
创作过程中难免有不足,若您发现本文内容有误,恳请不吝赐教。 提示:以下是本篇文章正文内容,下面案例可供参考 一、计算类对象的大小 #include<iostream> using namespace std;class Date { public:void Init(int year, in…...
【从零开始的LeetCode-算法】3232. 判断是否可以赢得数字游戏
给你一个 正整数 数组 nums。 Alice 和 Bob 正在玩游戏。在游戏中,Alice 可以从 nums 中选择所有个位数 或 所有两位数,剩余的数字归 Bob 所有。如果 Alice 所选数字之和 严格大于 Bob 的数字之和,则 Alice 获胜。 如果 Alice 能赢得这场游…...
一种简单高效的RTSP流在线检测方法,不需要再过渡拉流就可以获取设备状态以及对应音视频通道与编码格式
平台如何检测一路RTSP流是否在线? 在之前的流媒体平台方案中,我们都是通过定时RTSP拉流的方式,走一个完整的RTSP流程:包括OPTIONS、DESCRIBE、SETUP、PLAY、RTP收流,这种方式去取流,然后取到流之后进行流解…...
24/11/22 项目拆解 艺术风格转移
我们有时候想把两种艺术风格整合,创造更具艺术特色的艺术品,人很难办到,但是人工智能可以,比如下面将艺术画的风格转移到照片上。 我们先来初步了解一下实现上述功能的数学原理 所谓艺术风格,其实就是边缘,颜色&#…...
数字赋能,气象引领 | 气象景观数字化服务平台重塑京城旅游生态
在数字化转型的浪潮中,旅游行业正以前所未有的速度重塑自身,人民群众对于高品质、个性化旅游服务需求的日益增长,迎着新时代的挑战与机遇,为开展北京地区特色气象景观预报,打造“生态气象旅游”新业态,助推…...
关于Redux的学习(包括Redux-toolkit中间件)
目录 什么是 Redux ? 我为什么要用 Redux ? 我什么时候应该用 Redux ? Redux 库和工具 React-Redux Redux Toolkit Redux DevTools 拓展 一个redux小示例 代码示例(很有用): Redux 术语 Actions Reducers Store Dis…...
【无人机】
GJI Mini 4 Pro学习 首次飞行使用 01 开箱 打开长飞套装 依次取出产品及配件 飞行器、DJI RC - N2(DJI RC 2)、桨叶/螺丝、云台保护罩、束桨器、电池、螺丝刀、USB-C快接线、单肩包、USB-C数据线、充电管家 02 准备飞行器 取下束桨器,…...
Zabbix7.0.6的容器镜像准备
准备Zabbix7.0.6部署所需的容器镜像。 更新时间:20241122 一、准备数据库镜像 1、核对版本支持 根据Zabbix官网文档requirements 可知,当前最新的Zabbix 7.0.6对PostgreSQL数据库的要求如下: support for PostgreSQL versions:- 17.X …...
利用 GitHub 和 Hexo 搭建个人博客【保姆教程】
利用 GitHub 和 Hexo 搭建个人博客 利用 GitHub 和 Hexo 搭建个人博客一、前言二、准备工作(一)安装 Node.js 和 Git(二)注册 GitHub 账号 三、安装 Hexo(一)创建博客目录(二)安装 H…...
React第四节 组件的三大属性之state
前言 状态 state适用于类式组件中,而再函数式组件中需要使用 useState HOOK 模拟状态; React的组件就是一个状态机,通过与用户的交互,实现不同的状态,根据不同的状态展现出不一样的UI视图 并不是组件中所有的属性 都是组件的状态…...
MongoDB进阶篇-索引(索引概述、索引的类型、索引相关操作、索引的使用)
文章目录 1. 索引概述2. 索引的类型2.1 单字段索引2.2 复合索引2.3 其他索引2.3.1 地理空间索引(Geospatial Index)2.3.2 文本索引(Text Indexes)2.3.3 哈希索引(Hashed Indexes) 3. 索引相关操作3.1 查看索…...
使用FFmpeg实现视频与GIF的画中画效果
用FFmpeg命令行工具将GIF动画作为画中画(Picture-in-Picture,简称PiP)叠加到视频上。FFmpeg是一个强大的多媒体框架,能够处理几乎所有格式的音频和视频文件。通过这个教程,你将学会如何将一个小的GIF动画循环播放&…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
毫米波雷达基础理论(3D+4D)
3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文: 一文入门汽车毫米波雷达基本原理 :https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...
