declare type ClassDecorator = <TFunction extends Function>(
target: TFunction
) => TFunction | void;
declare type PropertyDecorator = (
target: Object,
propertyKey: string | symbol
) => void;
declare type MethodDecorator = <T>(
target: Object,
propertyKey: string | symbol,
descriptor: TypedPropertyDescriptor<T>
) => TypedPropertyDescriptor<T> | void;
declare type ParameterDecorator = (
target: Object,
propertyKey: string | symbol,
parameterIndex: number
) => void;
log
class C {
@log
double(n: number) {
return n * 2;
}
}
// method decorator log
function log(target: Function, key: string, desc: any) {
return {
value(...args: any[]) {
const result = desc.value.apply(this, args);
console.log(
`Call: ${key}(${args.map(arg => JSON.stringify(arg)).join()})`
);
return result;
}
};
}
// client
const instance = new C();
c.double(5);
Try to explain below questions from the yield code:
__decorate
function declared?"use strict";
var __decorate =
(this && this.__decorate) ||
function(decorators, target, key, desc) {
var c = arguments.length,
r =
c < 3
? target
: desc === null
? (desc = Object.getOwnPropertyDescriptor(target, key))
: desc,
d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
r = Reflect.decorate(decorators, target, key, desc);
else
for (var i = decorators.length - 1; i >= 0; i--)
if ((d = decorators[i]))
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
// method decorator log
function log(target, key, desc) {
return {
value(...args) {
const result = desc.value.apply(this, args);
console.log(
`Call: ${key}(${args.map(arg => JSON.stringify(arg)).join()})`
);
return result;
}
};
}
class C {
double(n) {
return n * 2;
}
}
__decorate([log], C.prototype, "double", null);
// client
const instance = new C();
c.double(5);
A parameter decorator should only be used to generate some sort of metadata. Once the metadata has been created we can use another decorator to read it.
interface Dto {
test: string;
}
function logType(target: any, key: string) {
console.log(
`${key}: ${Reflect.getMetadata("design:type", target, key).name}`
);
}
function logParameterType(target: any, key: string) {
console.log(
"logParameterType",
Reflect.getMetadata("design:paramtypes", target, key)
);
console.log(
"logParameterType",
`${key}: ${Reflect.getMetadata("design:paramtypes", target, key).map(
t => t.name
)}`
);
}
function logReturnType(target: any, key: string) {
console.log(
"logReturnType",
`${key}: ${Reflect.getMetadata("design:returntype", target, key)}`
);
}
class C {
@logType
public c: string;
@logParameterType
@logReturnType
public operation(param1: string, param2: string, param3: Dto): string {
return param1 + param2;
}
}
// client
new C();
// yield
// c: String
// logReturnType operation: function String() { [native code] }
// logParameterType (3) [ƒ, ƒ, ƒ]
// logParameterType operation: String,String,Object