装饰器依赖注入,元数据键是关键
因此必须开启ts装饰器和ts元数据
tsconfig.json
"experimentalDecorators": true, // 开启装饰器
"emitDecoratorMetadata": true, // 开启元数据
并且安装 reflect-metadata
支持元数据编程
全局入口倒入一次即可
import "reflect-metadata";
类型元数据:使用元数据键 “design:type”(用来获取属性类型)
参数类型元数据:使用元数据键 “design:paramtypes”(用来获取参数类型)
返回值类型元数据:使用元数据键 “design:returntype”(用来获取返回值类型)
使用
Reflect.getMetadata('design:type', target, propertyKey); // 获取被装饰属性的类型
Reflect.getMetadata("design:paramtypes", target, propertyKey); // 获取被装饰的参数类型
Reflect.getMetadata("design:returntype", target, propertyKey); // 获取被装饰函数的返回值类型
一般 design:returntype
用不上
design:type
用来实现 多次注入 只创建一个实例
design:paramtypes
用来获取构造函数的参数类型 去查找注入design:type
依赖类
最小案例:
这个案例只是验证构造函数自动注入能力 没有使用到design:type
const mockList = new MockList();
console.log(mockList.getList(3))
type Constructable<T> = new (...args: any[]) => T;
/**
* @description 将有参类转成无参类
* 参数 自动注入
*/
function Injectable<T extends { new (...args: any[]): {} }>(target: T) {
const constructorParams = Reflect.getMetadata("design:paramtypes", target);
if (constructorParams.length) {
return class extends target {
constructor(...args: any[]) {
const params: any[] = args.concat(
constructorParams.map((paramType: Constructable<any>) => {
return new paramType();
})
);
super(...params);
}
};
}
return target;
}
class Random {
color() {
return `#${Math.floor(Math.random() * 0xffffff)
.toString(16)
.padEnd(6, (Math.random() * 0xf).toString(16)[0])}`;
}
}
@Injectable
class MockList {
constructor(private random?: Random) {}
getList(count: number) {
return Array.from(new Array(count)).map((_, index) => ({
color: this.random?.color() ?? "woc",
index,
}));
}
}