写在前面的话
本文只讲解 TypeScript 中的装饰器语法(下称注解), 只会告诉你如何编写一个自定义注解,且通过注解简单的修改逻辑,不涉及 反射 或 元编程 等其他更进一步的代码讲解,如果有兴趣可以自行搜索相关的进阶写法,比如这位:
开始
注1:装饰器仅用于 class 语法中,所以以下举例中只会使用 class 写法。(其实是我只测试了 class 语法中的使用,而且也没必要在普通方法上使用注解)
注2:tsconfig.json 中 target 必须为 ES5 或以上版本。且 experimentalDecorators 与 emitDecoratorMetadata 字段需为 true
由于我们写的是 TypeScript,我们首先定义几个 interface 和 type ,让 IDE 有一些基本提示:
type Prototype = {
constructor: Function
} & any
type Constructor = { new(...args: any[]): {} };
interface FunctionAnnotation {
(target: Prototype, propertyKey: PropertyKey, descriptor: TypedPropertyDescriptor): void;
}
interface ConstructorAnnotation {
(constructor: T): T;
}
interface PropertyAnnotation {
(target: Prototype, propertyKey: PropertyKey): void;
}
interface ParameterAnnotation {
(target: Prototype, propertyKey: PropertyKey, parameterIndex: number): void;
}
其中,PropertyKey 和 TypedPropertyDescriptor 都在 lib.es5.d.ts 文件中有定义,其值为:
declare type PropertyKey = string | number | symbol;
interface TypedPropertyDescriptor {
enumerable?: boolean;
configurable?: boolean;
writable?: boolean;
value?: T;
get?: () => T;
set?: (value: T) => void;
}
如果有人不喜欢泛型写法,也可以将 TypedPropertyDescriptor 替换成 PropertyDescriptor
interface PropertyDescriptor {
configurable?: boolean;
enumerable?: boolean;
value?: any;
writable?: boolean;
get?(): any;
set?(v: any): void;
}这里使用泛型仅仅是因为我不喜欢 any,Prototype 类型中加上 any 是因为没有办法只能用 any,原因是类型定义中没有办法用 symbol 类型的值定义成 key,否则就可以写成 type Prototype = {[key: string]: Function; [key: number]: Function; [key: symbol]: Function;} 了
如果有人不知道 PropertyDescriptor 是干嘛的,请参考 Object.defineProperty()
下面我们直接用例子教你如何自定义一个注解。
方法注解
写法:
export function logFuncCall(): FunctionAnnotation {
return function (target, propertyKey, descriptor) {
if (typeof descriptor.value &