Typescript装饰器标准语法(区别于传统语法)

130 阅读1分钟

装饰器介绍

TypeScript 中的装饰器可以分为类装饰器方法装饰器访问符装饰器属性装饰器,最常见的主要还是类装饰器、方法装饰器以及属性装饰器。

类装饰器

function AddMethod() {
  return (originalClass: any, context: DecoratorContext) => {
    if (context.kind === "class") {
      originalClass.prototype.newInstanceMethod = () => {
        console.log("Let's add a new instance method!");
      }
      originalClass.newStaticMethod = () => {
        console.log("Let's add a new static method!");
      };
    }
  }
}

function AddProperty(value: string) {
  return (originalClass: any, context: DecoratorContext) => {
    if (context.kind === "class") {
      originalClass.prototype.newInstanceProperty = value
      originalClass.newStaticProperty = `static ${value}`
    }
  }
}

function OverrideFoo (originalClass: any, context: DecoratorContext) {
  return class extends originalClass {
    constructor(...args: any[]) {
      super(...args)
    }
    printMessage() {
      console.log("hello world")
    }
  }
}

@OverrideFoo
@AddProperty("hello")
@AddMethod()
class Foo {
}

const foo = new Foo();
(foo as any).newInstanceMethod();
(Foo as any).newStaticMethod();
console.log((foo as any).newInstanceProperty);
console.log((Foo as any).newStaticProperty);
(foo as any).printMessage()

方法装饰器

function LoggedMethod(originalMethod: any, context: ClassMethodDecoratorContext) {
  const methodName = String(context.name);
  const replaceMethod = function(this: any, ...args: any[]) {
    console.log(`LOG: Entering method '${methodName}'.`);
    const result = originalMethod.call(this, ...args);
    console.log(`LOG: Exiting method '${methodName}'.`);
    return result;
  }
  return replaceMethod;
}

function Bound(originalMethod: any, context: ClassMethodDecoratorContext) {
  const methodName = context.name
  if (context.private) {
    throw new Error("'bound' cannot decorate private properties like ${methodName as string}.")
  }
  context.addInitializer(function() {
    (this as any)[methodName] = (this as any)[methodName].bind(this);
  })
}
class Person {
  constructor(public name: string) {}

  @LoggedMethod
  @Bound
  greet() {
    console.log(`Hello, my name is ${this.name}`)
  }
}

const person = new Person("John");
const greet = person.greet;
greet()

属性装饰器

function Prefix(_: any, context: ClassFieldDecoratorContext) {
  if (context.kind === "field") {
    return function(initialValue: any) {
      return `hello, my Name is ${initialValue}`
    }
  }
}
class Person {
  @Prefix
  name = "yutt"
}
const person = new Person()
console.log(person.name)