Я пытаюсь создать собственный декоратор для цыринга, чтобы вводить через свойства.
Мой код:
import '@abraham/reflection';
import {container} from 'tsyringe';
/**
* Inject class through property
*
* @param targetClass
* @returns PropertyDecorator
*/
export const inject = (targetClass: new (...args: any[]) => any): PropertyDecorator => {
if (!targetClass || targetClass === undefined) {
throw new Error(`${targetClass} class is undefined`);
}
return (target: any, propertyKey: string | symbol): PropertyDecorator => {
return Object.defineProperty(target, propertyKey, {
get: () => container.resolve((targetClass))
});
};
};
Услуга
import { injectable } from 'tsyringe';
@injectable()
export class Test {
constructor() {
console.info('hi from test');
}
a(): void {
console.info('a');
}
b(): void {
console.info('b');
}
}
Класс вызова
import React, { ReactElement } from 'react';
import Head from 'next/head';
import { Test } from '../_service/test.service';
import { inject } from '../decorators/inject';
/**
* @class Home
*/
export default class Home extends React.Component {
@inject(Test)
private readonly test!: Test;
/**
* Render Home
*
* @returns ReactElement<any>
*/
render(): ReactElement<any> {
this.test.a();
this.test.b();
return (
<div>
<Head>
<title>home</title>
</Head>
<main>
<p>test</p>
</main>
</div>
);
}
}
Консольный вывод
hi from test
a
hi from test
b
Текущее поведение: каждый раз, когда я вызываю метод моего внедренного класса, мой конструктор вызывается снова. Это означает, что мой класс инициализируется при каждом новом вызове.
Когда я использую следующий код, кажется, что все работает
import React, { ReactElement } from 'react';
import Head from 'next/head';
import { Test } from '../_service/test.service';
import { container } from 'tsyringe';
/**
* @class Home
*/
export default class Home extends React.Component {
private readonly test: Test = container.resolve(Test);
/**
* Render Home
*
* @returns ReactElement<any>
*/
render(): ReactElement<any> {
this.test.a();
this.test.b();
return (
<div>
<Head>
<title>home</title>
</Head>
<main>
<p>test</p>
</main>
</div>
);
}
}
Консольный вывод
hi from test
a
b
Есть причины, почему это происходит?
После часа сна и большого количества кофе с некоторыми исследованиями... Я нашел решение!
Я пытался манипулировать геттером вместо установки значения свойства. Это привело к следующему коду:
/**
* Inject dependency through property
*
* @param targetClass
* @returns PropertyDecorator
*/
export const inject = (targetClass: InjectionToken): PropertyDecorator => {
if (!targetClass || targetClass === undefined) {
throw new Error(`${targetClass} class is undefined`);
}
return (target: any, propertyKey: string | symbol): PropertyDescriptor | undefined => {
if (!Reflect.deleteProperty(target, propertyKey)) {
throw new Error(`Could not delete property ${String(propertyKey)} in class ${target.constructor.name}`);
}
const options: PropertyDescriptor = {
value: container.resolve(targetClass)
};
if (!Reflect.defineProperty(target, propertyKey, options)) {
throw new Error(`Could not define ${String(propertyKey)} property in class ${targetClass.toString()}`);
}
return Reflect.getOwnPropertyDescriptor(target, propertyKey);
};
};