环境配置
TypeScript配置:
1 2 3 4 5 6 7 8 9 10
| { "compilerOptions": { "target": "ESNext", "experimentalDecorators": true, "emitDecoratorMetadata": true } }
|
使用装饰器+Reflect-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
| import "reflect-metadata";
export function metadataDecorator(target: any, propertyKey: string) { console.log(">>>"); console.log(Reflect.getMetadata("design:type", target, propertyKey)); console.log(Reflect.getMetadata("design:paramtypes", target, propertyKey)); console.log(Reflect.getMetadata("design:returntype", target, propertyKey)); }
export class Duty { private readonly name: string; private readonly createTime: number; constructor() { this.name = "duty info"; this.createTime = Date.now(); } }
export class Runner { @metadataDecorator private readonly version: string;
constructor() { this.version = "1.0.0"; }
@metadataDecorator run(duty: Duty): string { return ""; } }
|
上述代码的执行结果是:
1 2 3 4 5 6 7 8
| >>> [Function: String] undefined undefined >>> [Function: Function] [ [Function: Duty] ] [Function: String]
|
可以看出来:
design:type
代表成员类型
design:paramtypes
代表函数入参类型
design:returntype
代表函数返回类型
实现函数参数类型检查装饰器
实现一个用于检查函数的参数类型的装饰器:@paramTypeDecorator
。被装饰的函数,无须在函数内部显式的检查数据类型。
此装饰器的实现:
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
| const map = new Map(); export function paramTypeDecorator( target: any, propertyKey: string, descriptor: PropertyDescriptor ) { const paramTypes = Reflect.getMetadata( "design:paramtypes", target, propertyKey ); map.set(propertyKey, paramTypes);
const originalFunc = descriptor.value; descriptor.value = function (...args: any[]) { const paramTypes = map.get(propertyKey); for (let i = 0; i < args.length; ++i) { if (!(args[i] instanceof paramTypes[i])) { throw new TypeError( `Params[${i}] type should be ${paramTypes[i]?.name}` ); } } const result = originalFunc.call(this, ...args); return result; }; }
|
看下在Runner中的使用效果:
1 2 3 4 5 6 7 8 9 10 11
| export class Runner {
@paramTypeDecorator addDuty(duty: Duty) {} }
const runner = new Runner(); const duty = new Duty();
runner.addDuty(duty);
|
这段代码会正常运行,类型检查成功。如果最后一句换成:runner.addDuty({} as any)
,那么会报错,输出:TypeError: Params[0] type should be Duty