1. declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;
  2. declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void;
  3. declare type MethodDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void;
  4. declare type ParameterDecorator = (target: Object, propertyKey: string | symbol, parameterIndex: number) => void;

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

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

当存在多个装饰器来装饰同一个声明时,则会有以下的顺序:

  1. 首先,由上至下依次对装饰器表达式求值,得到返回的真实函数(如果有的话)
  2. 而后,求值的结果会由下至上依次调用 (有点类似洋葱模型) ```typescript function foo() { console.log(“foo in”); // 1 return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
    1. console.log("foo out"); // 4
    } }

function bar() { console.log(“bar in”); // 2 return function (target, propertyKey: string, descriptor: PropertyDescriptor) { console.log(“bar out”); // 3 } }

class A { @foo() @bar() method() {} }

// foo in // bar in // bar out // foo out

  1. <a name="cuUIK"></a>
  2. # Reflect Metadata
  3. <a name="AsWn8"></a>
  4. ## 使用条件
  5. 目前想要使用,我们还需要安装`reflect-metadata`与在`tsconfig.json`中启用`emitDecoratorMetadata`选项
  6. ```typescript
  7. // 入口文件 index.ts
  8. import 'reflect-metadata';
  1. // tsconfig.json
  2. {
  3. "compilerOptions": {
  4. "experimentalDecorators": true,
  5. "emitDecoratorMetadata": true,
  6. }
  7. }

为类或类属性添加了元数据后,构造函数的原型(或是构造函数,根据静态成员还是实例成员决定)会具有[[Metadata]]属性,该属性内部包含一个Map结构,键为属性键,值为元数据键值对。

  1. Reflect.defineMetadata(metadataKey, metadataValue, target[, propertyKey])
  2. // 其数据结构可表示如下:
  3. WeakMap {
  4. target: Map {
  5. propertyKey: Map {
  6. metadataKey: metadataValue
  7. }
  8. }
  9. }

内置元数据

在 tsconfig.json 中开启了 emitDecoratorMetadata 选项,此时,TypeScript 在编译时定义一些 元数据设计键(TypeScript 夹带的私货,目前babel并没有此feature),目前可用的有:

  1. 属性类型元数据 design:typeReflect.getMetadata("design:type", target, key)用于获取类属性的类型
  2. 参数类型元数据 design:paramtypesReflect.getMetadata("design:paramtypes", target, key)用于获取方法参数的类型
  3. 返回类型元数据 design:returntypeReflect.getMetadata("design:returntype", target, key)用于获取返回值的类型 ``typescript const MyClassDecorator: ClassDecorator = (target: any) => { const type = Reflect.getMetadata('design:type', target); console.log(类[${target.name}] design:type = ${type && type.name}); const paramTypes: any[] = Reflect.getMetadata('design:paramtypes', target); console.log(类[${target.name}] design:paramtypes =, paramTypes && paramTypes.map(item => item.name)); const returnType = Reflect.getMetadata('design:returntype', target) console.log(类[${target.name}] design:returntype = ${returnType && returnType.name}); }; // @ts-ignore const MyPropertyDecorator: PropertyDecorator = (target: any, key: string) => { const type = Reflect.getMetadata('design:type', target, key); console.log(属性[${key}] design:type = ${type && type.name}); const paramTypes: any[] = Reflect.getMetadata('design:paramtypes', target, key); console.log(属性[${key}] design:paramtypes =, paramTypes && paramTypes.map(item => item.name)); const returnType = Reflect.getMetadata('design:returntype', target, key); console.log(属性[${key}] design:returntype = ${returnType && returnType.name}); }; // @ts-ignore const MyMethodDecorator: MethodDecorator = (target: any, key: string, descriptor: PropertyDescriptor) => { const type = Reflect.getMetadata('design:type', target, key); console.log(方法[${key}] design:type = ${type && type.name}); const paramTypes: any[] = Reflect.getMetadata('design:paramtypes', target, key); console.log(方法[${key}] design:paramtypes =, paramTypes && paramTypes.map(item => item.name)); const returnType = Reflect.getMetadata('design:returntype', target, key) console.log(方法[${key}] design:returntype = ${returnType && returnType.name}); }; // @ts-ignore const MyParameterDecorator: ParameterDecorator = (target: any, key: string, paramIndex: number) => { const type = Reflect.getMetadata('design:type', target, key); console.log(参数[${key} - ${paramIndex}] design:type = ${type && type.name}); const paramTypes : any[] = Reflect.getMetadata('design:paramtypes', target, key); console.log(参数[${key} - ${paramIndex}] design:paramtypes =, paramTypes && paramTypes.map(item => item.name)); const returnType = Reflect.getMetadata('design:returntype', target, key) console.log(参数[${key} - ${paramIndex}] design:returntype = ${returnType && returnType.name}); }; @MyClassDecorator class MyClass { @MyPropertyDecorator myProperty: string; constructor (myProperty: string) { this.myProperty = myProperty; } @MyMethodDecorator myMethod (@MyParameterDecorator index: number, name: string): string { return${index} - ${name}`; } }

// 结果 // 属性[myProperty] design:type = String // 属性[myProperty] design:paramtypes = undefined // 属性[myProperty] design:returntype = undefined // 参数[myMethod - 0] design:type = Function // 参数[myMethod - 0] design:paramtypes = [ ‘Number’, ‘String’ ] // 参数[myMethod - 0] design:returntype = String // 方法[myMethod] design:type = Function // 方法[myMethod] design:paramtypes = [ ‘Number’, ‘String’ ] // 方法[myMethod] design:returntype = String // 类[MyClass] design:type = undefined // 类[MyClass] design:paramtypes = [ ‘String’ ] // 类[MyClass] design:returntype = undefined

  1. <a name="5Iarf"></a>
  2. ## **基本类型序列化**
  3. - `number` 序列化为 `Number`
  4. - `string` 序列化为 `String`
  5. - `boolean` 序列化为 `Boolean`
  6. - `any` 序列化为 `Object`
  7. - `void` 序列化为 `undefined`
  8. - `Array` 序列化为 `Array`
  9. - 如果是`Tuple`,序列化为`Array`
  10. - 如果`class`将它序列化为类构造函数
  11. - 如果`Enum`序列化为`Number`或者`String`
  12. - 如果至少有一个呼叫签名,则序列化为 `Function`
  13. - 否则序列化为`Object`(包括接口)
  14. <a name="mnOBB"></a>
  15. ## 简单实现IOC
  16. ```typescript
  17. import 'reflect-metadata';
  18. type Constructor<T = any> = new (...args: any) => T
  19. type Decorator = ClassDecorator | PropertyDecorator | MethodDecorator | ParameterDecorator
  20. type Token = string | symbol | Constructor | Function
  21. interface IProvider {
  22. type: 'class' | 'value'
  23. value: any
  24. instance?: any
  25. }
  26. const TYPE = 'design:type'
  27. const PARAMTYPES = 'design:paramtypes'
  28. const RETURNTYPE = 'design:returntype'
  29. // const RETURNTYPE = 'ioc:key'
  30. class Provider implements IProvider {
  31. constructor(public readonly type: 'class' | 'value', public readonly value: any) {
  32. }
  33. }
  34. class Container {
  35. private map = new Map<Token, IProvider>()
  36. inject(token: Token, provider: IProvider) {
  37. this.map.set(token, provider)
  38. }
  39. get<T>(token: Token): T {
  40. const { map } = this
  41. if (map.has(token)) {
  42. const provider = map.get(token)!
  43. if (provider.type === 'value') {
  44. return provider.value
  45. }
  46. if (provider.type === 'class') {
  47. if(provider.instance) return provider.instance
  48. const instance = new provider.value()
  49. provider.instance = instance
  50. return instance
  51. }
  52. throw new Error('未知type'+ provider.type)
  53. } else {
  54. console.log('================');
  55. console.log('providers >>>>>>', map);
  56. console.log('================');
  57. throw new Error('找不到' + token.toString())
  58. }
  59. }
  60. }
  61. const container = new Container();
  62. container.inject('val', new Provider('value', 'val'))
  63. function Injectable(token?: Token): ClassDecorator {
  64. return (target) => {
  65. console.log('================');
  66. console.log('target >>>>>>', target);
  67. console.log('================');
  68. // 用token 或者用类作key
  69. container.inject(token ?? target, new Provider('class', target))
  70. }
  71. }
  72. function Value(token?: Token): PropertyDecorator {
  73. return (target, propertyKey) => {
  74. Object.defineProperty(target, propertyKey, {
  75. get() {
  76. return container.get(token ?? propertyKey)
  77. }
  78. })
  79. }
  80. }
  81. function Inject(token?: Token): PropertyDecorator {
  82. return (target, propertyKey) => {
  83. const type = Reflect.getMetadata(TYPE, target, propertyKey);
  84. console.log('================');
  85. console.log('type >>>>>>', type);
  86. console.log('================');
  87. Object.defineProperty(target, propertyKey, {
  88. get() {
  89. return container.get(token ?? type)
  90. }
  91. })
  92. }
  93. }
  94. interface ITest {
  95. test(): void
  96. }
  97. const ITest = Symbol('ITest')
  98. @Injectable(ITest) // 至少要有一个装饰器
  99. class Test implements ITest{
  100. @Value('val')
  101. private readonly valTest!: string
  102. test() {
  103. console.log('================');
  104. console.log('valTest is', this.valTest);
  105. console.log('================');
  106. }
  107. }
  108. @Injectable()
  109. class TestMachine {
  110. @Inject(ITest)
  111. readonly test!: Test;
  112. run() {
  113. this.test.test()
  114. }
  115. }
  116. const testMachine = new TestMachine();
  117. testMachine.run()
  118. // ================
  119. // target >>>>>> [Function: Test]
  120. // ================
  121. // ================
  122. // type >>>>>> [Function: Test]
  123. // ================
  124. // ================
  125. // target >>>>>> [Function: TestMachine]
  126. // ================
  127. // ================
  128. // valTest is val
  129. // ================