一、命令行
1 |
tsc index.ts –target ES5 -w –experimentalDecorators –emitDecoratorMetadata |
二、Decorator Composition
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
function f() { console.log('f(): evaluated') return function (target: any, propertyKey: string, descriptor: PropertyDecorator) { console.log('f(): called') } } function g() { console.log('g(): evaluated') return function (target: any, propertyKey: string, descriptor: PropertyDecorator) { console.log('g(): called') } } class C { @f() @g() method() {} } // console输出结果 // f(): evaluated // g(): evaluated // g(): called // f(): called |
三、Class Decorators
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
function sealed(constructor: Function) { console.log(Object, constructor) Object.seal(constructor) Object.seal(constructor.prototype) console.log(Object) } @sealed class Greeter { greeting: string constructor(message: string) { this.greeting = message } greet() { return 'hello, ' + this.greeting } } // console输出结果 // [Function: Object] [Function: Greeter] |
四、Method Decorators
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
function enumerable(value: boolean) { return function (target: any, propertyKey: string, descriptor: PropertyDecorator) { console.log(target, propertyKey, descriptor) descriptor.enumerable = value // 重定义函数 descriptor.value = function () { console.log('overwritten') return 'bob' } console.log(descriptor) } } function time(name: string) { return function (target: any, propertyKey: string, descriptor: PropertyDecorator) { const fn = descriptor.value descriptor.value = (...args) => { console.time(name) const v = fn(...args) console.timeEnd(name) return v } } } class MGreeter { greeting: string constructor(message: string) { this.greeting = message } @enumerable(false) greet() { return 'hello, ' + this.greeting } @time('MGreeter.method') method(name: string) { console.log('method called', ...arguments) for (let i = 0; i < 100000; i++) {} } } let mg = new MGreeter('bob') console.log(new MGreeter('bob').greet()) // 函数被重定义后,输出 bob mg.method('bob', 'smith') // console输出结果 // [Function: Object] // MGreeter { greet: [Function], method: [Function] } greet { // value: [Function], // writable: true, // enumerable: true, // configurable: true // } // { // value: [Function], // writable: true, // enumerable: false, // configurable: true // } // overwritten // bob // method called bob smith // MGreeter.method: 3.883ms |
五、Accessor Decorators
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
function configurable(value: boolean) { return function (target: any, propertyKey: string, descriptor: PropertyDecorator) { 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 } } let p = new Point(1, 2) console.log(p.x, p.y) // console输出结果 // 1 2 |
六、Property Decorators
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
const formatMetadataKey = Symbol('format') console.log('formatMetadataKey', formatMetadataKey) function format(formatString: string) { return Reflect.metadata(formatMetadataKey, formatString) } function getFormat(target: any, propertyKey: string) { return Reflect.getMetadata(formatMetadataKey, target, propertyKey) } class PGreeter { @format('Hello, %s') greeting: string constructor(message: string) { this.greeting = message } greet() { let formatString = getFormat(this, 'greeting') return formatString.replace('%s', this.greeting) } } let pg = new PGreeter('property decorators') console.log(pg.greet()) // console输出结果 // formatMetadataKey Symbol(format) // Hello, property decorators |
七、Parameter Decorators
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
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 console.log('validate', method) descriptor.value = function () { let requiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyName) console.log(requiredParameters) 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) } } class ParamGreeter { greeting: string constructor(message: string) { this.greeting = message } @validate greet(@required name: string) { return 'Hello ' + name + ', ' + this.greeting } } let paramGreeter = new ParamGreeter('bob') // console.log(paramGreeter.greet()) // execute throw new Error('Missing required argument.') console.log(paramGreeter.greet('smith')) // console输出结果 // validate [Function] // [ 0 ] // Hello smith, bob |
八、Metadata
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
class MPoint { x: number y: number } function metadataValidate<T>(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) { let set = descriptor.set console.log(descriptor) descriptor.set = function (value: T) { let type = Reflect.getMetadata('design:type', target, propertyKey) console.log(type) if (!(value instanceof type)) { throw new TypeError('Invalid type.') } set.call(target, value) } } class Line { private _p0: MPoint private _p1: MPoint @metadataValidate set p0(value: MPoint) { this._p0 = value } get p0() { return this._p0 } set p1(value: MPoint) { this._p1 = value } get p1() { return this._p1 } } let mline = new Line() mline.p0 = new MPoint() mline.p0.x = 1 mline.p0.y = 2 console.log(mline.p0) // console输出结果 // { // get: [Function: get], // set: [Function: set], // enumerable: false, // configurable: true // } // [Function: MPoint] // MPoint { x: 1, y: 2 } |