ts装饰器(注解)

简介: ts装饰器(注解)

书,能保持我们的童心;书能保持我们的青春。——严文井

官方文档:https://www.typescriptlang.org/docs/handbook/decorators.html

这个东西在java里叫注解,不过在ts中,一个装饰器对应一个方法

首先执行命令:

tsc --target ES5 --experimentalDecorators

然后配置一下tsconfig.json就可以使用了

{
    "compilerOptions": {
        "target": "ES5",
        "experimentalDecorators": true
    }
}

首先我们定义一个class

class User {
  private id: Number | undefined;
  private name: string | undefined;
}

我们编写一个装饰器对应的逻辑,实现javalombok@Data生成gettersetter

function Data(constructor: Function | ObjectConstructor) {
  console.log('@Data', { constructor })
  Object.getOwnPropertyNames(new constructor()).forEach(key => {
    const firstUpperProperty = key.charAt(0).toUpperCase() + key.substring(1)
    if (!constructor.prototype[`get${firstUpperProperty}`]) {
      constructor.prototype[`get${firstUpperProperty}`] = function () {
        return this[key]
      }
    }
    if (!constructor.prototype[`set${firstUpperProperty}`]) {
      constructor.prototype[`set${firstUpperProperty}`] = function (value: any) {
        this[key] = value
      }
    }
  })
}

我们将这个注解放到类的上面

@Data
class User {
  private id: Number | undefined;
  private name: string | undefined;
}

尝试调用一下

const user = new User()
user.setId(1);
user.setName("John");
console.log(user.getId());      // 1
console.log(user.getName());    // "John"

可以看到确实生效,这里打印的参数:

顺带一提注解可以以复数形式存在,上方文档提到了,这里就不多赘述

我们继续编写注解,刚刚这个是类装饰器

接下来来个给默认的getter方法获取时,如果没有就提供一个默认值的注解@DefaultVal

这是一个属性装饰器

function DefaultVal(val: any) {
  return function (target: any, key: string) {
    console.log('@DefaultVal', { target, key, val });
    const firstUpperProperty = key.charAt(0).toUpperCase() + key.substring(1)
    target.constructor.prototype[`get${firstUpperProperty}`] = function () {
      return this[key] ?? val
    }
  };
}

注意优先级,我们的属性装饰器优先级高于我们的类装饰器,所以getter别被覆盖了

类中不同声明上的装饰器将按以下规定的顺序应用:

  1. 参数装饰器,然后依次是方法装饰器访问符装饰器,或属性装饰器应用到每个实例成员。
  2. 参数装饰器,然后依次是方法装饰器访问符装饰器,或属性装饰器应用到每个静态成员。
  3. 参数装饰器应用到构造函数。
  4. 类装饰器应用到类。

使用方式:

@Data
class User {
  private id: Number | undefined;
  @DefaultVal('nobody')
  private name: string | undefined;
}

演示:

console.log({ 'new User().getName()': new User().getName() });

输出结果:

{'new User().getName()': 'nobody'}

打印参数:

然后是方法装饰器

这里我们指定返回值不能为null,否则报错

function NonNull() {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log('@NonNull', { target, propertyKey, descriptor });
    let value = descriptor.value
    descriptor.value = () => {
      const result = value.call()
      if (result === null || result === undefined) throw new Error(`${propertyKey} must non-null`)
      return result
    }
  };
}

使用:

@Data
class User {
  private id: Number | undefined;
  @DefaultVal('nobody')
  private name: string | undefined;
  @NonNull()
  toString() {
    // return Object.prototype.toString();
    return null
  }
}

测试:

new User().toString();

打印结果:

最后是参数装饰器

这里懒得写了,就输出下日志吧:

function Log(target: Object, propertyKey: string | symbol, parameterIndex: number) {
  console.log('@Log', { target, propertyKey, parameterIndex });
}

使用:

@Data
class User {
  private id: Number | undefined;
  @DefaultVal('nobody')
  private name: string | undefined;
  @NonNull()
  toString() {
    return Object.prototype.toString();
    // return null
  }
  equals(@Log val: User) {
    return deepEqual(this, val);
  }
}

打印:

相关文章
|
5月前
|
存储 JavaScript 算法
TS泛型类型
TS泛型类型
52 0
|
JavaScript
对TS里泛型的理解
对TS里泛型的理解
62 1
|
JavaScript 前端开发
ts - 类
TypeScript支持JavaScript的新特性,比如支持基于类的面向对象编程。让我们创建一个Student类,它带有一个构造函数和一些公共字段。 注意类和接口可以一起工作。
|
JavaScript
ts - 重载
重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。
ts - 泛型
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
|
JavaScript 编译器 开发者
ts的接口是什么有什么作用
ts的接口是什么有什么作用
348 0
|
缓存 监控 JavaScript
面试题-TS(八):什么是装饰器(decorators)?如何在 TypeScript 中使用它们?
在TypeScript中,装饰器(`Decorators`)是一种用于增强代码功能的特殊类型声明。装饰器提供了一种在类、方法、属性等代码元素上注释或修改的方式,使得我们可以通过装饰器来扩展、修改或监视代码的行为。通过使用装饰器,我们可以在不修改原始代码的情况下,给代码添加新的功能,提高代码的可维护性和灵活性。
|
JavaScript
【TS】ts的使用和类型注解
【TS】ts的使用和类型注解
123 0
TS在实际开发中的使用
TS在实际开发中的使用
76 0