装饰器依赖注入,元数据键是关键
因此必须开启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,
}));
}
}
使用design:type
/**
* @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>) => {
const getInstance = Reflect.getMetadata(
"inject:class",
paramType
);
if (getInstance) {
return getInstance;
}
const instance = new paramType();
Reflect.defineMetadata(
"inject:class",
instance,
paramType
);
return instance;
})
);
super(...params);
}
};
}
return target;
}
class RandomNumber {
constructor() {
console.log("init RandomNumber");
}
number() {
return Math.random();
}
}
@Injectable
class Random {
constructor(private randomNumber: RandomNumber) {
console.log("init Random");
}
color() {
return `#${Math.floor(this.randomNumber.number() * 0xffffff)
.toString(16)
.padEnd(6, (this.randomNumber.number() * 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,
}));
}
}
@Injectable
class MockList2 {
constructor(private random2?: Random) {}
getList(count: number) {
return Array.from(new Array(count)).map((_, index) => ({
color: this.random2?.color() ?? "woc",
index,
}));
}
}
const mockList = new MockList();
console.log(mockList.getList(3), mockList);
const mockList2 = new MockList2();
console.log(mockList2.getList(3), mockList2);
可以看到 init Random 只执行了一次