TypeScript装饰器学习

简介: 使用装饰器可以装饰一个类或类中的属性在不修改装饰对象中的源代码的情况下改变装饰目标的行为

测试环境


下面的实践均采用ts编写,使用ts-node直接运行,需在全局安装typesciptts-node


全局安装依赖


npm i typescript ts-node -g


运行ts文件


ts-node xx.ts


类装饰器


装饰器对象是一个类


function classDecorator(target){
    return target
}
@classDecorator
class C{
    hello(){
        console.log('hello world')
    }
}


  • target表示装饰的目标类

示例:在目标类上拓展 sayHello 方法


function helloWorld(target){
    // target === 目标类
    target.prototype.sayHello = function(){
        console.log('hello world');
    }
    return target
}
@helloWorld
class Router {
    sayHello() {
        throw new Error("Method not implemented.");
    }
}
const r = new Router()
r.sayHello() // hello world


函数装饰器


装饰对象的值是一个函数


function funDecorator(target, name, descriptor){
    return descriptor.value
}
class C{
    @funDecorator
    hello(){
        console.log('hello world')
    }
}


  • target: 目标类的原型
  • name: 属性名
  • descriptor:属性描述符号
  • value:属性值
  • writable:是否可以被重写
  • enumerable:是否可枚举
  • configurable:是否可配置


示例:提示某个方法已经失效


function expired(target, name, descriptor): any {
    console.log('fun:',name, 'is expired');
    return descriptor.value
}
@helloWorld
class Router {
    @expired
    hello() {
        // ...code
    }
    @expired
    hello2(){
        // ...code
    }
}
// fun: hello is expired
// fun: hello2 is expired


get/set装饰器


装饰存/取器的装饰器


  • target: 静态方法指向类的构造函数,实例方法指向类的原型
  • name: 属性名
  • descriptor:属性描述符号
  • value:属性值
  • writable:是否可以被重写
  • enumerable:是否可枚举
  • configurable:是否可配置


function getDecorator(target,name,descriptor){
}
function getDecorator(target,name,descriptor){
}
class C{
    private _x: number
    private _y: number
    constructor(x, y) {
        this._x = x
        this._y = y
    }
    @getDecorator
    get x() {
        return this._x
    }
    @getDecorator
    get y() {
        return this._y
    }
    @setDecorator
    set x(v) {
        this._x = v
    }
    @getDecorator
    set y(v) {
        this._y = v
    }
}


emmmm,暂没想到用武之地


属性装饰器


简而言之就是装饰对象是一个普通的属性,参数和上述函数装饰器一致

函数也可以看做是类的一个属性,只不过其属性值是function


function propertyDecorator(target,name){
}
class C{
    @propertyDecorator
    private property:string|undefined
}


示例:设置默认值


function defaultValue(v: any) {
    return function (target, name) {
        target[name] = v
    }
}
class Router {
    @defaultValue('666')
    public name: string | undefined
}
const r = new Router()
console.log(r.name);


其中装饰器传参实现,可以看做是一个闭包调用


在设置装饰器的时候传递参数,然后返回一个函数去真正装饰目标对象


这个被装饰的对象可以使用传递的参数


函数参数装饰器


顾名思义,装饰对象是函数中的一个参数


function paramDecorator(target,name,idx){
}
class C{
    fun1(@paramDecorator a){
    }
    static func2(@paramDecorator a){
    }
}


  • target: 静态方法指向类的构造函数,实例方法指向类的原型
  • name:属性名
  • idx:参数在函数中所处位置


示例:获取参数在函数中的相对位置


function printParamPos(target, name, idx) {
    console.log('paramCount:', target[name].length, 'paramPos:', idx);
}
class Router {
    hello3(@printParamPos name: string) {
        console.log('hello3', name);
    }
    static hello4(@printParamPos name: string) {
        console.log('hello4', name);
    }
}
const r = new Router()
Router.hello4('123')
r.hello3('456')
// paramCount: 1 paramPos: 0
// paramCount: 1 paramPos: 0
// hello4 123
// hello3 456


实例


这里参考了一下core-decorators中的源码


弃用API提示


/**
 * 弃用指定API提示
 * @param msg 
 * @returns 
 */
export function deprecate(msg = 'This function will be removed in future versions.') {
    return function (target, key, descriptor) {
        const methodSignature = `${target.constructor.name}#${key}`;
        return {
            ...descriptor,
            value: function () {
                console.warn(`DEPRECATION ${methodSignature}: ${msg}`);
                return descriptor.value.apply(this, arguments);
            }
        };
    }
}


测试代码


import { deprecate } from './decorators/index'
class TestClass {
    @deprecate()
    hello(name: string) {
        console.log('hello', name);
    }
}
const a = new TestClass()
a.hello('world')


运行结果:


DEPRECATION TestClass#hello: This function will be removed in future versions.
hello world


参考



未完待续


后面和大家一起学习一下 core-decorators 中的源码,学习一下常用的优秀的装饰器设计


相关文章
|
5天前
|
JavaScript 前端开发 数据安全/隐私保护
TypeScript中装饰器的概念与使用场景
【4月更文挑战第23天】TypeScript的装饰器是特殊声明,用于附加到类的声明、方法、属性或参数,以修改行为。它们以`@expression`形式,其中`expression`是运行时调用的函数。装饰器应用场景包括:日志记录、调试、依赖注入、权限控制和AOP。通过装饰器,可以实现动态行为修改,如添加日志、注入依赖、控制权限以及事务管理。然而,应谨慎使用,避免过度复杂化代码。装饰器在现代 TypeScript 开发中扮演重要角色,帮助编写更健壮、可维护的代码。
|
5天前
|
JavaScript 前端开发 编译器
TypeScript【泛型1、泛型2、声明合并、命名空间 、模块1、模块2、声明文件简介】(五)-全面详解(学习总结---从入门到深化)
TypeScript【泛型1、泛型2、声明合并、命名空间 、模块1、模块2、声明文件简介】(五)-全面详解(学习总结---从入门到深化)
69 0
|
5天前
|
存储 JavaScript 前端开发
TypeScript 5.2 beta 浅析:新的关键字 using 与新版装饰器元数据
TypeScript 5.2 beta 浅析:新的关键字 using 与新版装饰器元数据
|
5天前
|
编解码 JavaScript 前端开发
TypeScript【第三方声明文件、自定义声明文件、tsconfig.json文件简介、tsconfig.json 文件结构与配置】(六)-全面详解(学习总结---从入门到深化)
TypeScript【第三方声明文件、自定义声明文件、tsconfig.json文件简介、tsconfig.json 文件结构与配置】(六)-全面详解(学习总结---从入门到深化)
75 0
|
5天前
|
JavaScript
TypeScript【类的继承、访问修饰符、readonly 修饰符、存取器、实例方法与静态方法、实例属性与静态属性、静态属性、抽象类】(三)-全面详解(学习总结---从入门到深化)
TypeScript【类的继承、访问修饰符、readonly 修饰符、存取器、实例方法与静态方法、实例属性与静态属性、静态属性、抽象类】(三)-全面详解(学习总结---从入门到深化)
22 0
|
5天前
|
缓存 JavaScript 前端开发
【TypeScript技术专栏】TypeScript中的装饰器与元编程
【4月更文挑战第30天】TypeScript的装饰器是元编程工具,用于修改类、方法等行为。它们允许实现日志、权限控制、缓存等功能,支持类装饰器、方法装饰器等多种类型。装饰器借助JavaScript的Proxy和Reflection API实现,但过度使用可能造成复杂性。正确运用能提升代码质量,但需注意类型安全和维护性。
|
5天前
react+typescript装饰器写法报错的解决办法
react+typescript装饰器写法报错的解决办法
24 1
|
5天前
|
存储 JavaScript 前端开发
TypeScript笔记(15)—— 深入理解TypeScript中的装饰器
TypeScript笔记(15)—— 深入理解TypeScript中的装饰器
58 0
|
5天前
|
JavaScript
如何使用 TypeScript 创建和使用装饰器
如何使用 TypeScript 创建和使用装饰器
21 0
|
5天前
|
JavaScript 前端开发 编译器
TypeScript【泛型1、泛型2、声明合并、命名空间 、模块1、模块2、声明文件简介】(五)-全面详解(学习总结---从入门到深化)(下)
TypeScript【泛型1、泛型2、声明合并、命名空间 、模块1、模块2、声明文件简介】(五)-全面详解(学习总结---从入门到深化)
31 0
TypeScript【泛型1、泛型2、声明合并、命名空间 、模块1、模块2、声明文件简介】(五)-全面详解(学习总结---从入门到深化)(下)