装饰器

介绍

随着 TypeScript 和 ES6 中类的引入,现在存在某些需要附加功能来支持注释或修改类和类成员的场景。装饰器提供了一种为类声明和成员添加注释和元编程语法的方法。装饰器是 JavaScript 的 第 2 阶段提案,可作为 TypeScript 的实验性功能使用。

注意 装饰器是一项实验性功能,可能会在未来的版本中发生变化。

要启用对装饰器的实验性支持,您必须在命令行或 tsconfig.json 中启用 experimentalDecorators 编译器选项:

命令行

tsc --target ES5 --experimentalDecorators

tsconfig.json

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

装饰器

o3fxb2gG80QosCkjKX+9ZIDT8jQVw9iMirvD1/AjPMAHTdAnknaRGP9Ra2rfeYw/+b8OKHSExyLwCbjRo78irGSIrvrmkHavIUbKLDQX1O2KfRovKLFEwYgX0F+/2uJxuyHx3iCuCTL53Svt/VVhxKisRpg5SlCUGkyH69zh3SVXlffZKUl/h9xIFuT72ZD2me0l2gSq7wKGqSLcITFgchwY6bip9HktyFtA76PKf9au47FjLVt5G+hO5G2AQxBc+kRrDIq/EfgiVooUVgdm+awscz5A7jvyuD+MMjtVOHkto+hWLk+ZtjCrjGaiI1gZJwmgPABQ0EBfRTmCekMhjtV6ebnj1CQ4hR/XvWJKAV32fLcNzK+gYY8FexFbYbGNNjW+sQyP6XWH4kpth1jZaMGrjBYKcPUIxOlRoL5xWTZQhyHJS4yDV+GHW4Rr4Emsq9k3TROB91eunsCQ5BZ47Zz3nf8CFAxVbpczqWvEnDrtBWPqSLMhez/6RJQlsR0YdY6sSvC42K5hEmv6oS+VlR+p75XBPqeeQ7z+628FIBouyzcVlJcIc0QFzabPJ8qfSfRCuX1vOMadlXv0zjVfIgyo2HgHUEBib5mx7QgmBef4SuVTopxvqWiohI7F9ge1v2ydtFAj8qg+YK7LT5ROLtEJK2RcI0idSUthSVE8jrOzI2BS8FJ0ZMlOJqgOFxjarwtp3yftNgykiaDRCVaC0A==

4mrTNjElZgxiA3lRHd8tZihwQeBl66rZtwirlnSviT7MGYAQIejXz8ntbrrYw9iIirNJk2qZy6nxAAd4HCo53/cPTvVjZrijvrESYDtkmypzcoMKRxpeVtRMopyyCOY4BxdYdDHHw1A+eOJivG2ADQ==

function sealed(target) {
  // do something with 'target' ...
}

装饰器工厂

IQ2giPobtI3qLMfSn9gapbeg2MGjgwBxeL57YNTTanfaFUbDxAgrPK4J4ng7kYJMJOUfYOeIWi/oJTY99T63s/B+958foLBj2+tZpMaxWJNDzg72YXVP/Gt747/VJrUjMaz+3blWlyyLsH1J8hYkesshT5w6efG2eJrxDw0OPLWBKyt2xOqKJnrMce4DQcQIfCmzWUoZg05wLRA0nTf0vVagqNynYI8XzY0Ff76htkQRB8DapTVLG6sBwkbTCGbcbEDQibfgpSREdWOXVWUw4Q==

Q6bK7LzXK2POD9khcBgOCjggyx0m/2bAyt9U20+ksslGdgliX+v1ACMSDCXjXRbJIrFW17hJFKok/IcSOK4LQA==

function color(value: string) {
  // this is the decorator factory, it sets up
  // the returned decorator function
  return function (target) {
    // this is the decorator
    // do something with 'target' and 'value'...
  };
}

装饰器组成

W/tCMyqQpfbbPHHtX1JaBAhLbq0FDRqk4oimi8zgQxQF1YpkeMQV/9WZlovkKlzxy/w2zaXexcHpUoX+P8NEKQ==

function f() {}
function g() {}
@f @g x

xaXuhDGJuK8gOFRKEFQ/4Q==

function f() {}
function g() {}
@f
@g
x

O2T3jN+HKEYLL/31OJsdKRM4+uAwtZD1IxvIPgw2j2s/vbclhU+kRxpLuVr0szH0Lg3utZtLtOnqT58EB+2BmYG+4O02HyKP9Tqhbq+nMyFSscx7jnhOEnfNqxJHkT6TxMZ/5ON01m3GqC2L/zN5pEoHqiVwSBcwII0QilAxeynFTqNNNiF8/6D2MHmKmXjksJd0oSpWHBppuRDX2rx+Qc7c36yjTALF+FcATm5xGjbasp6eoH3uR/cwYyRtMtxcO6IZPtIVcK+55v4jCFIY2cwZBxpsgrPNN0wJNmmfUZpf49i3JgrU2uUM/bPSXiDAGPEiF11jsXm0aX/q4gPV1g==

NHT1w+HFFOogMjDaPRigvhy6hAqtbcFWz47v5vA7VQY212FPHDAay9sJ/9G2R5dFB2UWOq3+l6rnh7YRekJ79XlSbL3e8SBB+CWUvcqlwL6z6vEzL1HqV9k/PwpAKah3

  1. 每个装饰器的表达式都是从上到下计算的。
  2. 然后将结果作为函数从下到上调用。

rNOSvm5DJH/Bu+HPi+i07jkXaVAp0iTsQ4DSDf/Mr7MS+meVmBCqPv3Ssvm+Uon02PNtBcFH+1NARfJqHvTXjm7/GoNIKCChboF0WBRZYG63wIzPuiJghF9Tt4D9JycsbVDHWrYUGMbP/rHMhiwusktJ19x6q/dxd6lrky2cNrrOrQBPuRQyN338jIrA2hcO

function first() {
  console.log("first(): factory evaluated");
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log("first(): called");
  };
}

function second() {
  console.log("second(): factory evaluated");
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log("second(): called");
  };
}

class ExampleClass {
  @first()
  @second()
  method() {}
}

11fUEHPyXRpCmg7yyy3sAoWa+EjOYWdwElWX5TYXs8K6/q0l4jlpnHGNpOEuxxK0

first(): factory evaluated
second(): factory evaluated
second(): called
first(): called

装饰器评价

F/tkTrmz7hK6pMXhky9OMG9SN5xMpfVOORB/rM9OJXM6BP+jXEn6cwefBmBBRcSJXQHzZfZ7MWlCBAYyC/IVW6IA33EVK3Kqkrj03UbbHPjHxnpQxIe6n0HBHrJOsrIq

  1. 参数装饰器,后跟方法、访问器或属性装饰器应用于每个实例成员。
  2. 参数装饰器,后跟方法、访问器或属性装饰器应用于每个静态成员。
  3. 参数装饰器应用于构造函数。
  4. 类装饰器应用于类。

类装饰器

IUsDEpcEDTNUjUBMMTkU9HVepjQ+y3knJ7GFdGOvXRkNNDNHCxgRZSwCRp4NyQU1MD8yii+PAXrkXLhAMFqch9UI0wKxKZUv1SJlG82rjmBdjFadpd3szSsTYFz/jU5aA0GTPPVb/o2xxU0/CBznu6rIVvCMcuBCcibLEPt99PBNCtST8ejE0TJ0uTk9EmVzpv5LuKXBAANFHY2SwzaevIYL6kGVHjHbysojqy4eu0mCh6TZHCrHPnyDZbhjYBwLBtdSFOdWX/CycNtOrAqvMPvZ04LKh4oD1R6I9SeA9TuNDj+7eumA03+DSpfpdJpfzzarFobYsOhQqdQvU81DdA==

le8a+NeNn3yMlXI7Ju8ETJJDD+Jp9GjYqfQLAXKwNtxTo0OxC1rIqQUZXqQ/uj5Z8BeoEfyoe9ux7lBHqlsZwHzvytPE2bgNHZ45Y0NIZyhSm4E7egeoGGMJ0U9WiF/xtiQVN8iP6M95eFndy4m6TQ==

R3ekuByTQlOh+920bTBZ0csgSgL5bjlVc3LVrI6nnH2D23ZMFPhuVFHH6PsrQWYjz/zOK4UhmdDWBTARLstvNJVAZRtPp/K+WkthcNCgRqix3Fd7At4G5cmnNlr1THOv

rR9BxcxmvAHVptJGY9xXWNPwwwuO9AuGkVV41tFCMEx2WYXndOe6t4P20kM2QOJ3zuj3CUB54JgJ871ISwRpHxbAbEGRyD7t1PyNUHxycYOec1bFf1HmOmjw+gIsEV7NflptxBQ0S2fBCKWjjBEE3PPZ8gUjAwKpp/hjMjoaCLAOV1kFv/yGiVZ8IUy+Prmp9cP+hK1PXll0ZITucfSjhRZGm2ShORRXKhz1mwJFNdU=

8gE+JRACalRqviqXRrwVPJvDom9ccr3/NNZk32veu1I7eAQjR2VhqeIEFooHZ1wZctwBsYooXGXZIWMmIjrB6HVeKiyts5BT1DrbIrBis+Cr7z2Zoq0g+VTv6I7/7Jc/zfHQV8W1yrDKWc+yzjKs6g==

function sealed(constructor: Function) {
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}
@sealed
class BugReport {
  type = "report";
  title: string;

  constructor(t: string) {
    this.title = t;
  }
}

D8hMSmaW2zu8E5bzOEF36naXLxEQBYXV9bwcXtCumk3JQreexlzOABn8KlPo1IKNGIz5pcLbndLJn+6Vmy5k7/1vKEeC8zN4xf4HWZtORFY=

function sealed(constructor: Function) {
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}

w/7GCvFnDU1ICJ4Fxp5P+a6xcmY8Oq8mPPfoMnIqgfX/ViJ7GGvvKTNYNxFsnOQxJvLRBWJVCA1p/KyB1u0Co7+1elbpegkCxs1BL5iAQbwCVf4KrFg1q7HmcLbZhCiqotnNh6cqUeKT88Hw9FEGjiboqAY1jlaKM4MXCAAtjWynJuIwTyzFBXWpLJ6/NF4HeDore4ukP5BmQBdWSkQH7CD6+VXqdYeJydecCWDQmN6yEmBxoAREeHIA1FcDnKIzV2pdD3IsqsjKWHqzsuYctstfEo+Z9N0fSpmq+2L9nqwBAclks72md7GiCvY5WevviZRozfzG/hCP54KxdV/fJ+Ma0MEdlEGhKr2NxPm5/N3poIV5h2nf6doBCw1WvX6exnqK4az9JFBHbR9FmS7FUYH3RUj0ai6tqQyd8EY5nv/UCoZbf6lFU+dx2S6rCWhFbGP5glNuDPKP/7P1/7cbVN6c8ojWB1rrIBKnU9Ly2dGGjU/O+O7lokpG6gnbKUUgamKDiTA0R5XSTcc0eLxajfL6VbotBOR7SXxkaEtL6/hCid7DT/SQzHMQycDZlOv+

nj21u+bT+U6m9RBNPJzmEI+8drrpukZWeRZRB9LarCETyeCtuZLHelv+88gzaUq2Z7c1bycPCsbUSlYSD9AgEDO2/nFFPEcDRD6GVvVkaAurzWMHP0u0X0RmaA3Ha2VL

function reportableClassDecorator<T extends { new (...args: any[]): {} }>(constructor: T) {
  return class extends constructor {
    reportingURL = "http://www...";
  };
}

@reportableClassDecorator
class BugReport {
  type = "report";
  title: string;

  constructor(t: string) {
    this.title = t;
  }
}

const bug = new BugReport("Needs dark mode");
console.log(bug.title); // Prints "Needs dark mode"
console.log(bug.type); // Prints "report"

// Note that the decorator _does not_ change the TypeScript type
// and so the new property `reportingURL` is not known
// to the type system:
bug.reportingURL;

方法装饰器

Wbqk2YueWVruo1dwEca4GKWkS/QS/k17UmYicol13/VtEBIU1hTInpIp4Oxi740A9ZxlOqUoyArijmq6Jyb6x6GAXOWEXLKw5Mn7X8+XyP6/IxyYnJC7R0vHpKBfByMi9CVDbJXTtoGVS6zIoq64xTbgbSgDoDbpfE/XwCmbAKLklQofxFdRGMmpTaxycKfwlpSgR61e283lbx/g1SB6bUrUW430I3j4HkTN2zZpliH2dXm6iRtiiA0G0GQNdqdR+b7j/XKVflvkuwJZGt/5OWaP+0kUqyqszQPn1wQUBiii/wG6MF56WpIdqu0QVoDAeml+pDuA18dyvw+dF4YyqCL8Wz5eEoklcL3cL5oie04=

FF0UCM8KhNfZixVKpvt5MBrEVuenrfWBOTkwD7I7hcRsLAtKZCQwTMiS/a7kZqoavWAOgzxnFY5EE4ES6Nh03Eci7Z+K12wEQEclwiKTvSGX19vkjN+A86BTIOBTmhmn

  1. 静态成员的类的构造函数,或者实例成员的类的原型。
  2. 成员的姓名。
  3. 成员的属性描述符。

lFt3UKbZu3Mi8w6IRaowA65/YBFxZCpAx6EWw3lsYXF5G6YRUj/JYqiajv9kXxXg7/bv5JWB9pteJ1T5Cg5/c0a0dUlgoy++Fdu2Is232e7PfX+v3d/paBbEFoCwhvFT0VkCcb52SDJNYQNjo66Muw==

ZyIMeyPZ7I07Y3RJDs+V31h7PuMEb2meZgLDXupXOVfMc6AWAaoasqCvQFobtv8mmtmx3FYr75kO9cWg2X973R9+fegTKOS0i1yA5E3OIzr3kLe+d7QbeC0wT2aqzyCw

lFt3UKbZu3Mi8w6IRaowA65/YBFxZCpAx6EWw3lsYXF5G6YRUj/JYqiajv9kXxXgaeizNCHwuI6M99QEp90wan8LQO0RJX32NNtFyCTeEOc7FaVGxnTBeB61XLkAbqXA

8gE+JRACalRqviqXRrwVPIZcw1/rddBhZLTDW3HyH6TXBHbhlu9s4JFMhqfD4igGUxqmJAh4OPysnQdIcMEaIqVUzvWGj9Q9StnloxAlfHug/3rwjBbQ2Dsfr1Ic+fjTp7M3NZUmlu8D37mzO9rfiQ==

function enumerable(value: boolean) {
  return function (target: any,propertyKey: string,descriptor: PropertyDescriptor) {
    descriptor.enumerable = value;
  };
}
class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }

  @enumerable(false)
  greet() {
    return "Hello, " + this.greeting;
  }
}

D8hMSmaW2zu8E5bzOEF36naXLxEQBYXV9bwcXtCumk3JQreexlzOABn8KlPo1IKNrmzsUj7wrovvNytP98Y6XGd0a71sl8cjP5fQ8S8YpBsNFKHwuADiOw/OSG1iHre0

function enumerable(value: boolean) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    descriptor.enumerable = value;
  };
}

Qi09s7/3jpHu32y37wbiuZGntkSyS1tsnQXcAPS+d4GfpS264hrPb14bhP6P4m9K/MTus1gmV9E4A/pqYONaF8fQeqrwG4U4Y2ZMwluLlMOMgHm+NVo+AaBxZXin6lyzjSdlu6kiDhu9f0k540ODnb/I31GIqKbwWSbck6ZJDL1WW7JF+U7eBvR0O3/tq4lKt2L6bi4vYRxkqljfYv1xslfAuTqarqzSKQ4mOkHqOL68qWKRDKmToVNCSk7nRtI3X+xcurBBQ559NTEvO+3vuM7vtFysXF6zTZBPmCG3dhEjilRxA8EKS0rktLNw9bd0Mehe2mywtzdiF1vMbQ45mg==

访问器装饰器

1EZx4adBLSm/bE4UX8MdR0zP8U5uatMoL7Nz7rEaeiEGxd/tUh2IGdXtNXK0x1V0qvoQf7STNCQ53q8WxArPsANkUDvplrK20q/mpici1uTA22jOuiyB6ljOTWrNBSG2peOFzmQ6o7KtWJJuEhSQtyo9wDU5KPXhN+pc67WmxY+z8Im6GXvSJINhNKOrBwvwLKXF3vUn2bLdr/rsz51ssxibr6EF6X2L/0U+jYt/QVGWZ3NdKscY45r07kjx6a2lb61mL6BKmmKU9zg8dArjEbtFJrG/aXQJ07juVBiuOGLy3rxL6cHSbbdMdA8ftawC7SYu0TdytZUXzFunijLzGBVIk0+KF9JIgxtwqN5KBEVGs9Q/LhgRpXHcFt2Ie40a

bup5xhlwcpbLYgeMSs5a1BAPS2XbTn70XWXDtXH9MnRY22pjLzQP+uNJiWXlNzSwegWWn9EJR59stldxxBWbT0MmjBHS0VL/s0b3Q0cSpdWI1Mpn4EfJYGcN9bxeW2Og3pLpm12E5RsRE6PBN6PDGp9AA5CXdpScZTPN57QYmQsgXE9o1ba6RX+eqYa/+emnu2M0NpQFsgg1PcqklFxGaFEld72EvJxETYsXMP6BQAD/LhHYeXW2SeIdpl0jMhCZsHTki53mARJUWiyOsCfy05dEs4ZvMSHcKbnFf8ogXWbgmOVTjjg+NnmIiKKDFl6Yl4XuP+Aa99Ow/JVBu5a91q+9is2l+ytsqwG6rM/NqcjM4Uihp30Do4M8YJkchiZ73KLyZcooTHpTrd7BZx7AFQmQ4WMDs4KsS3lymbRV3i8o2tBOU1bVidWe/6qEAmaNQ3E8mJ7cRXMsIPUgniJqXw==

1EZx4adBLSm/bE4UX8MdR+svoY9f+7yx8PEoUS+3QHCFHT0+vutogWEnzkjEjQlkyvWBFPRM790+yeQctzjTnfcXiHuCM2AlnDoRL4dE5HUJO4rvuiF8Djbz750LoFNKkjJnagc1sg3wJxbifpq6sw==

  1. 静态成员的类的构造函数,或者实例成员的类的原型。
  2. 成员的姓名。
  3. 成员的属性描述符。

lFt3UKbZu3Mi8w6IRaowA65/YBFxZCpAx6EWw3lsYXF5G6YRUj/JYqiajv9kXxXg7/bv5JWB9pteJ1T5Cg5/c0a0dUlgoy++Fdu2Is232e7PfX+v3d/paBbEFoCwhvFT0VkCcb52SDJNYQNjo66Muw==

ItaavYqURUDhplpz7ryEA5rDf+Kb9/ANjNRG9pvYlQjV/HCKFdxFB2+UJWslfceuiFBETHxBekjM3GpFOiAQyOpUanoaSxohsXpAPJqBet5Wq9MsAxC8yvTvdTZppY4N

lFt3UKbZu3Mi8w6IRaowA65/YBFxZCpAx6EWw3lsYXF5G6YRUj/JYqiajv9kXxXgaeizNCHwuI6M99QEp90wan8LQO0RJX32NNtFyCTeEOc7FaVGxnTBeB61XLkAbqXA

8gE+JRACalRqviqXRrwVPBgGUqGXEWX7eC6jyPC0htfNH/NNPtmRLs38pXdfCO9LtTNObZXhz5d7tUJbolVF+ca+t0Qc+zobVUI2BBIUqzorXYswfKKEV/XrcG8D7p6ymWpuC9j5RY9KFOicTFlhrQ==

function configurable(value: boolean) {
  return function (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ) {
    descriptor.configurable = value;
  };
}
class Point {
  private _x: number;
  private _y: number;
  constructor(x: number, y: number) {
    this._x = x;
    this._y = y;
  }

  @configurable(false)
  get x() {
    return this._x;
  }

  @configurable(false)
  get y() {
    return this._y;
  }
}

D8hMSmaW2zu8E5bzOEF36naXLxEQBYXV9bwcXtCumk3JQreexlzOABn8KlPo1IKNLXw3ebZ84hOuH0ZzSwjx3aEWPZm/KBl/yZHMecaj0B+45jrQHfiK6XSSnaTtXo1Q

function configurable(value: boolean) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    descriptor.configurable = value;
  };
}

属性装饰器

+LioaS6mm6SNtg0Hzaceb0mdvsJ7q+eoi5I57hsGfaQCY2ABjMa98tjBDF2ZbjBam2kg9LI4bLQYZBThTPSv3Mbk57ZAHv4eIzwklWYZkjxEL5Re679PdvfSg4Dt9LcJUqVw9II2P8CAzJrycWpNX5ih5lcoB7/WZCDOHcb+NQd9+fTJJ/uITWsVYiNFr2Q3Fr+W2TWigGwFN80Mfhup9ZGa5LCWnsh0FZY9/ewvBO4=

iclDvjyJoPYe2oWMqeDtGJuUGWzVFfPJZgG/K3TrpRBlRA1UO4bsSz1y0DknHKSdvLD5IDy11EyOcH7LD84LDB1cLOnHPQ9JmJLBQW/DKMTJ6Rvp5Jtz3MPYqgyBcbIi

  1. 静态成员的类的构造函数,或者实例成员的类的原型。
  2. 成员的姓名。

tm1Bsbs7jHN0rsSsPDmHZnl2BYw/vjuKbCC1HT9iu9kU/46wqP8VyKVnON7mViC6g40Nj0hbw1eDO++d+7JXzRWFUXUGqkGhp0tX+OhZsM9QGHUZCMPtJdbNxKr83mTkCqZyImr2U1Bqo5W2FU4DT1e5aJIxNSXx7dRcEy9lcddry0QCjEWPlgo8oOhTI0waGp3GZB/rBIhExbyKSFCG+6oQCC1B1hN287C2QUoPtM/+j25xFWsPGuNt0iOK8fsBIfdrhFA3SkDZBsTiJEM9TvJdxUhJtCFMiin4qw8+4+tdRNk9IvbphI1CY5e6dRwkE0/VGzlTJVCbIcHp9o1h0smJoU0lMHG1Uwle3F2AGv4BkwypA6LDY56stNpWsq7ZLHHOaNlJ5wd/eWZQOCDc7i3vfnOmR1Z5+MNl4fD3LGtR+49/zffIrO7Z/PEGCNTo6JdCctS+wT1IDxc8v1hwDuXoUofmFbL3AFvPVteLvaerN57mXpDRbybTIpRmHQGC

D8hMSmaW2zu8E5bzOEF36nrH5C9yjz4ClO0IZeEjaRY3tGw+7kOIEflk6s0UCHJQXJcgTpya51LSFYbDCn/ayQctNZh4wW73AZM/YYbJBbzo3sndyYGCleug+e9hqJM5

class Greeter {
  @format("Hello, %s")
  greeting: string;

  constructor(message: string) {
    this.greeting = message;
  }

  greet() {
    let formatString = getFormat(this, "greeting");
    return formatString.replace("%s", this.greeting);
  }
}

us+MFmlit/XJwZmi89apGFhuYYeyUgprbbtM3yQrawl8swR+8A8x8rRi4FHP25N9Qk+B6gjn47/selaX+Nxn9i+3897tDuhINx2g3oEl6M21CrqPm+jIvIKPEOqj8f8eynnTiNs6F03U2F+gqCiyf3R9JXsMGBu1kHNoysaHnIU=

import "reflect-metadata";

const formatMetadataKey = Symbol("format");

function format(formatString: string) {
  return Reflect.metadata(formatMetadataKey, formatString);
}

function getFormat(target: any, propertyKey: string) {
  return Reflect.getMetadata(formatMetadataKey, target, propertyKey);
}

Qi09s7/3jpHu32y37wbiuTMygboGQgvAP9wNZdi9pSrxapoQNknE/gBRNEBQHE/yA2uppFRTap9y7//LQIMc9ItPTAFGgQT+gF0ywmX5iNV4RjK/xwKR/PhVlCIn8O/GiEBtA7r302C2ikav8oMiyvsnN0wr/jAXshXzkFsGOUfyo+3h5DWH0d6UFC0fIehQbic7spG2Sx1VJ+SBnyq3CgCC0uaJSq0KLUxSq0eRL78WfU/R90iZw7EHBkOpZq8HneUut1FD3k0etvlLiujLEXW/DPr9Ae8kb2HPeZBVDuVcg01xmK8IwRDoi+5g2pl2FLO9vHvc+M+j+KPk3Y5C5SFzv+EJYtFfgzYV8fsW/bJX+I8a/pPP/4sjykvn0b+TtHQjunUhppaz/EBdwJWowPHjmv+c4SZAWVqTCxnkFh0GvQ0l4QscqnvO+gdYQk/KwGHpOIrgWlPkRO7aN8jKGQ8IcgxDs40eqNOAscKkOpdS/Ha56usUozT0haIUBUS0

X70dA1tN+6/2D0w/qZRUdbtK1MVp0eeJuGVe3QwypINdtEpZR8Ygik2jQf6bDCXD/4LgoqF2OWHwzO4XfK0nuegJr1lAIwq/LHCChLFaR53sh8JVx9sDTjAoFxUuHcVWDSqqOpX8pjVLwmncHq0ZgPr/z9h/DD51fSN2uhmd8ioTa3h7BvP9Pn5d4iMQwOAWKOwJ3gG1IV2yxNDeqJOYjiDSrnPzpswXCttCAak8TKrMAEGAz0TXg5OJeKEF8riZ

参数装饰器

PtpO9T90mQeSsTpbsxclLNMOOpZCXf2kHUYc7Y2Yg9dXPRlDb9okGknCs6Nv6DhzmntEwURz94GlNo40jepGGbs7Euo7cpN2ClS3tgGZgRAd8kbIfi7waNyjAsWJEi/CwsFpYCSvoe+DROS4ypqL5dHeKltcG0etIbmkI8zmGkTyTKIZRFAMibL0LpUqzt4AiWCpgnT3kmvDs+vIuP7XHnZ5DmxNa+7YlGGFePql+ZHchhKyoVh6c4k8Z68yvjXSLDCJqWKFTivfK+Bhw0bnnoDuLJrIlhriR0cmJ/D9ELPA1agU+gbwN9EdxvjFyHF5B3BgBnRvJIe4NH5JTJo9Kg==

X+b6P3ujrZj16kV5W22oxjI9FuaTNzy/NDKLLGxnZ6EDcdm2GUblOaPlLjbqGVqWEGd7vekhxYKDjBPfqcGnDsgmtJvsWlJcMqdDxVooAr+Qzo76q5fxoj99PwYE9jFb

  1. 静态成员的类的构造函数,或者实例成员的类的原型。
  2. 成员的姓名。
  3. 函数参数列表中参数的序号索引。

ebstWo7JZe3/h9lvSqWsJU6ZdEGeBtENJ0EEF4STC9xKBLGNhPpDba7Db8U+dWwcZ4uBYUDzpU0f0yABQF9+oKZ3xlvHrGBiVSshcLm6nww=

X+b6P3ujrZj16kV5W22oxgLtQmXmWNv51NCQdNlU8j9Hm20Kq/neZC5rFayNLj6o

8gE+JRACalRqviqXRrwVPJvDom9ccr3/NNZk32veu1Ksw+BsE/Gxd+4mwnikwhpyKNoU2mh4tI+Fp2E4XswbBIKh6l/loBFMRddYo1Mb+RMYpnVKYxF3fu9zgM2ydh+MHQtsE4uarP6nwHf7XciXYGqoPbz3L7LGQcgfiyyiIPI=

function validate(target: any, propertyName: string, descriptor: TypedPropertyDescriptor<any>) {}
function required(target: Object, propertyKey: string | symbol, parameterIndex: number) {}
class BugReport {
  type = "report";
  title: string;

  constructor(t: string) {
    this.title = t;
  }

  @validate
  print(@required verbose: boolean) {
    if (verbose) {
      return `type: ${this.type}\ntitle: ${this.title}`;
    } else {
     return this.title; 
    }
  }
}

us+MFmlit/XJwZmi89apGFhuYYeyUgprbbtM3yQrawl8swR+8A8x8rRi4FHP25N9Qew6edAD5NSHKstAN8cE93WXFa5aIwX1d1m2pWGxtMcFZbo9tIe1oHbQkPkBa6l17jKjsaiXIiflAZydbtHFPyP9u192BxzCGASL0jSU8wA=

import "reflect-metadata";
const requiredMetadataKey = Symbol("required");

function required(target: Object, propertyKey: string | symbol, parameterIndex: number) {
  let existingRequiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyKey) || [];
  existingRequiredParameters.push(parameterIndex);
  Reflect.defineMetadata( requiredMetadataKey, existingRequiredParameters, target, propertyKey);
}

function validate(target: any, propertyName: string, descriptor: TypedPropertyDescriptor<Function>) {
  let method = descriptor.value!;

  descriptor.value = function () {
    let requiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyName);
    if (requiredParameters) {
      for (let parameterIndex of requiredParameters) {
        if (parameterIndex >= arguments.length || arguments[parameterIndex] === undefined) {
          throw new Error("Missing required argument.");
        }
      }
    }
    return method.apply(this, arguments);
  };
}

Z/XSj9G141ZIUEjYE2Kl+Yhq/E4zPZmDYR+a+3el62N9XrC0HIIeRa9loHyXqDvFT1+FZJ4L08JLxMC55Uk7v9uCq6Yi6KjbsJ9jNwAMDV84kuyK4148EGGhMTNsbgQYvNU8wuU7Hhsoz/zTbqdCbINYKM4n4iLaklIHdaGmmv1UgSAoBnDdNpl5LBHGkV2gSXVVjodP03UrypD6tMjpY+nDxu4IXVxuDzUQet6jJr6KxQrEsZpucA3o6E5lMVu2LHHRS5g7z6F664ToY6TRWolc7buCPfe1G3+np90C8CfyXB7Ei7XVRfPb45MpFJqiSujLW8Avj4QLHqEm8914xUQ3QWisKlnPHG16kSYui1A=

X70dA1tN+6/2D0w/qZRUdbtK1MVp0eeJuGVe3QwypINdtEpZR8Ygik2jQf6bDCXD/4LgoqF2OWHwzO4XfK0nuegJr1lAIwq/LHCChLFaR53sh8JVx9sDTjAoFxUuHcVWDSqqOpX8pjVLwmncHq0ZgPr/z9h/DD51fSN2uhmd8ioTa3h7BvP9Pn5d4iMQwOAWKOwJ3gG1IV2yxNDeqJOYjiDSrnPzpswXCttCAak8TKrMAEGAz0TXg5OJeKEF8riZ

元数据

IiztZBpTbdxhNSzWrup0kjuTrWbxmlgGfySCwFIOtT4DHyu567/iEZaarfxbVHIK3v7mxdHBNh46HE7tIsIT7CbemY7M8kCpERi8B/CvikjFYQ4ebRmInixYm6EKJhog81YAbo5N881m7do8azvxxF8ElnVzlfgKAv+xY07d1VV9L5FBHmWpUKSBUS6S//QiWvvIaS2degGW0DuRloXKI7eR0H3t/8uUoe350pk+qVqCyEDMNDrbs4/XGE1jWp36VAASgKEP6VNRBtUdc/Af1l8t8N9yIa2PoDM8u+/WHEzbAVy61aOIBtVh/Fz30esJzfgLKGIQZDToft9oX5yic2AM0n2TBP1jZ9PlRrn4lVgsGa3k1ZevRRPYjQJarOrsbqCx1VL8COVuLLm+YwDwyIx+V8rzgdTkdFCJYRYkcYCtZ5dMLMP5nDcTxQPL5LT+

DtuiSFsuC/ngo68vUqf0yCe0F37uTzxg9ideMMvjZon4b9RFdvcyYmvyKDuldrH7

npm i reflect-metadata --save

l07RsYclkRpou/mP59IZSD1wQGoMklNDEazrG9beJ0wjbKcIh0WeHHcdN1Lg9vw+fWMgxozHbjRwjRutRSrY//N5NOrvVZEMD1pjsKXiQJrkXVPb7Il5WvTwhv5bQ8bdb6u5LDu4BBCBV0Yf9SxCFf92GK4S8HX1fybtisnJHjae4Jkuie3iMIj8i2CFO6VpDQiADwN1Uv5ZO3Dvpcla+3X4v85bt/8TUQQa6pRCzvVMM+AQL+nvHABw7lnehMPnkyqX5qs+BdCsnIGlFvq7DK/kfxwAfN8ot097JIEnj/s9VvtudHkFS7gL6Ens2JdqcAiGRRXK25zjEbJBi5svzXmB97YGzM+Cv6jyggqh0haDIihV7mL9chhy9o08tmKMwIBNJwsZ9aaXxK3MeylRRg==

LVmpK5gi1Kwl7ME78JadPFV8ksAwvFhWQdLhodE2s34=

tsc --target ES5 --experimentalDecorators --emitDecoratorMetadata

E87U01gasrw6O20S1tQzWw8FjNwsnpF4A8XER1/IdRY0IEd298Truy02TvSYDcJ/

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

vB+xh8aLg+pUx6hqjBnzl58Kg3nvncuHMzsTTlND8xGhU3Eqn0QdA7SqnL1IOhYU9HbXlhplxFPPwH1yppuDmLwuAhKII86/YTGFB/9ZDQyFKPpPXNzCidGizKGa9vq4g7vhYGi7M2OAyxP2Ld1JE71FXHLI3wIrfLBiBgzNOAM=

w5LmJFTdF/yO5HGI9EFtOhSZ2OUEylAYKRqxlUJ4r78nA1lg9xTXLHH1NggSlxUEFqce3u8kMrsoXFl0VJfvBA==

import "reflect-metadata";

class Point {
  constructor(public x: number, public y: number) {}
}

class Line {
  private _start: Point;
  private _end: Point;

  @validate
  set start(value: Point) {
    this._start = value;
  }

  get start() {
    return this._start;
  }

  @validate
  set end(value: Point) {
    this._end = value;
  }

  get end() {
    return this._end;
  }
}

function validate<T>(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) {
  let set = descriptor.set!;
  
  descriptor.set = function (value: T) {
    let type = Reflect.getMetadata("design:type", target, propertyKey);

    if (!(value instanceof type)) {
      throw new TypeError(`Invalid type, got ${typeof value} not ${type.name}.`);
    }

    set.call(this, value);
  };
}

const line = new Line()
line.start = new Point(0, 0)

// line.end = {}

// Fails at runtime with:
// > Invalid type, got object not Point

QXrMPzlOkqSHkeVxgiISB2qY4WyQBFYHOftRy4q5cDsI4V6EMlMvY16p+POC6cDiuUhjeMzbXyFH0fGO0SB9vB/3duZnftvAI470noIpNybPLwIroc93hWVF+1PlSpFpNI7NUhLSahVqcMtZIkwYu7J/gH+f/KpwosqSXPvBqb+Bx3TEMuq50t0y8wlN3vEyhr02i/hRj0cg6B/SmdqJYQ==

class Line {
  private _start: Point;
  private _end: Point;

  @validate
  @Reflect.metadata("design:type", Point)
  set start(value: Point) {
    this._start = value;
  }
  get start() {
    return this._start;
  }

  @validate
  @Reflect.metadata("design:type", Point)
  set end(value: Point) {
    this._end = value;
  }
  get end() {
    return this._end;
  }
}

1q0D1S/6mjazlTjW54cwl6Ak4GrmYCDV65I2qzPSIhYW5LTHsryA4y4qXp43e0pXRNPZnTsWtV2nyF1fGx+juDDvzdCFhEvivAqdGgfowxJaznFURw3EY2VqM1HG207W8YokMnw4l6ZPqARHlVxuBg==