TS 装饰器产物分析
WARNING
TypeScript 目前有 2 个装饰器版本,一个是旧版,一个是新版。
- 旧版
5.0之前 - 新版
5.0之后,也就是 ECMASCript 官方的装饰器,文章。
本文章分析的是旧版的 TS 装饰器。
今天在阅读 一文速览 TypeScript 装饰器 与 IoC 机制 的时候,阅读到了:
属性装饰器
类似于 方法装饰器 ,但它的入参少了 descriptor (属性描述符) 。 原因则是目前没有方法在定义原型对象成员的同时,去描述一个实例的属性(创建描述符)。
TIP
descriptor (属性描述符) 不会做为参数传入属性装饰器,这与 TypeScript 是如何初始化属性装饰器的有关。 因为目前没有办法在定义一个原型对象的成员时描述一个实例属性,并且没办法监视或修改一个属性的初始化方法。 返回值也会被忽略。 因此, descriptor (属性描述符) 只能用来监视类中是否声明了某个名字的属性。
TS Origin
ts
function EditMethod(): MethodDecorator {
return (target, propertyKey, descriptor) => {
descriptor.writable = false
}
}
function EditProperty(): PropertyDecorator {
return (target, propertyKey) => {
console.log(target)
console.log(propertyKey)
}
}
class A {
@EditProperty()
originAttribute: number = 123
@EditMethod()
originMethod() {
console.log("I'm Original!")
}
}
const a = new A()TS Output
整理并去除 Reflect.decorate。
js
'use strict'
const __decorate = function (decorators, target, key, desc) {
let len = arguments.length
let result = void 0
if (len < 3) {
result = target
} else if (desc === null) {
// method 的 desc 是 null
desc = Object.getOwnPropertyDescriptor(target, key)
result = desc
} else {
// Property 的 desc 是 void 0
result = desc
}
let decorator = void 0
for (let i = decorators.length - 1; i >= 0; i--) {
decorator = decorators[i]
if (decorator) {
if (len < 3) {
// class
result = decorator(result)
} else if (len > 3) {
// method
result = decorator(target, key, result)
} else {
// property
result = decorator(target, key)
}
}
}
return len > 3 && result && Object.defineProperty(target, key, result), result
}
function EditMethod() {
return (target, propertyKey, descriptor) => {
descriptor.writable = false
}
}
function EditProperty() {
return (target, propertyKey) => {
console.log(target)
console.log(propertyKey)
}
}
class A {
constructor() {
this.originAttribute = 123
}
originMethod() {
console.log("I'm Original!")
}
}
__decorate([EditProperty()], A.prototype, 'originAttribute', void 0)
__decorate([EditMethod()], A.prototype, 'originMethod', null)
const a = new A()总结
在 TS 编译产物中, 我们可以看到, 方法装饰器 是通过 Object.getOwnPropertyDescriptor 拿到 Descriptor 的.
注意
js
const desc = Object.getOwnPropertyDescriptor(Print.prototype, 'originMethod')因为方法是定义在原型上的 (可以获取 target.prototype), 而属性却在实例里 (TS 目前无法获取他的运行时生成实例的 Descriptor).