TS 装饰器 ( Decorators )

96 阅读2分钟

随着TypeScript和ES6里引入了类,在一些场景下我们需要额外的特性来支持标注或修改类及其成员。 装饰器(Decorators)为我们在类的声明及成员上通过元编程语法添加标注提供了一种方式。

tsconfig.json

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

装饰器是一种特殊类型的声明,它能够被附加到类声明方法, 访问符属性参数

declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;
declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void;
declare type MethodDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void;
declare type ParameterDecorator = (target: Object, propertyKey: string | symbol | undefined, parameterIndex: number) => void;
类装饰器 ClassDecorator
const doc:ClassDecorator = (target:Function)=>{
    console.log(target)
    target.prototype.name = "zgy"
}
@doc
class A{
    constructor(){
    }
}

const a:any = new A()

console.log(a.name)

image.png

属性装饰器 PropertyDecorator
const doc:PropertyDecorator = (target: Function, propertyKey:string | symbol): void => {
  console.log(target, propertyKey);
};

class A {
  @doc
  name: string
  constructor(name) {
    this.name = name;
  }
}

const a: any = new A("zgy");

image.png

方法装饰器 MethodDecorator
const doc: MethodDecorator = (
  target: Object,
  propertyKey: string | symbol,
  descriptor: PropertyDescriptor
): PropertyDescriptor | void => {
  console.log(target, propertyKey, descriptor);
};

class A {
  name: string;
  constructor(name) {
    this.name = name;
  }
  @doc
  getName() {
    return this.name;
  }
}

const a: any = new A("zgy");

image.png

属性装饰器 ParameterDecorator
const doc: ParameterDecorator = (
  target: Object,
  propertyKey: string | symbol | undefined,
  parameterIndex: number
): void => {
  //parameterIndex =1 参数的下标
  console.log(target, propertyKey, parameterIndex);
};

class A {
  name: string;
  constructor(name) {
    this.name = name;
  }
  
  getName(a:string,@doc b:string) {
    return this.name+a+b;
  }
}

const a: any = new A("zgy");
a.getName("你好","世界")

image.png

Demo 封装axios Get Post装饰器

本示例采用NestJS
demo.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class DemoService {

  getList(){
    return [
      {
        title:'小张',
        id:1
      },
      {
        title:'小明',
        id:2
      },
      {
        title:'小红',
        id:3
      },
    ]
  }

  update(){
    return {
      code:200,
      message:'ok'
    }
  }


}

demo.controller.ts
import {
  Controller,
  Get,
  Post,
  Body,
  Patch,
  Param,
  Delete,
} from '@nestjs/common';
import { DemoService } from './demo.service';

@Controller('demo')
export class DemoController {
  constructor(private readonly demoService: DemoService) {}

  @Get('list')
  getList() {
    return this.demoService.getList();
  }

  @Post('update')
  update(@Body() updateData) {
    return this.demoService.update();
  }

  @Post('agreement')
  getXieyiBody(@Body() body) {
    let agreement = body.agreement
      .replace(/\*\*\*\*\*/, '')
      .replace(/&&&&&/, '');
    const list = agreement.split('@');
    let address = Number(list[0])
      .toString(16)
      .toLocaleUpperCase()
      .padStart(2, '0');
    let stakeMark = list[1];
    let orderCode = list[2];
    let data = list[3];
    console.log(
      `地址:${address},桩号:${stakeMark},执行码:${orderCode},数据:${data}`,
    );
  }
}

ts文件 装饰器的demo
import axios from 'axios'

const Get = (url:string) => {
  return (
    target: Object,
    propertyKey: string | symbol,
    descriptor: PropertyDescriptor
  ): PropertyDescriptor | void => {
    const fn = descriptor.value;
    axios
      .get(url)
      .then((res) => {
        fn({
            code:200,
            data:res.data,
            success:"ok"
        })
    })
      .catch((err) => {
        fn({
            code:500,
            data:null,
            success:"err"
        })
      });
  };
};

const Post = (url:string) => {
    return (
      target: Object,
      propertyKey: string | symbol,
      descriptor: PropertyDescriptor
    ): PropertyDescriptor | void => {
      const fn = descriptor.value;
      axios
        .post(url)
        .then((res) => {
          fn(res.data)
      })
        .catch((err) => {
          fn({
              code:500,
              data:null,
              success:"err"
          })
        });
    };
  };

class A {
  constructor() {}
  @Get("http://localhost:3000/demo/list")
  getList(data) {
    console.log("getList",data)
  }

  @Post("http://localhost:3000/demo/update")
  update(data){
    console.log("update",data)
  }
}

image.png