#typescript #decorator #typescript-decorator
#typescript #декоратор #typescript-декоратор
Вопрос:
Я пытаюсь немного поиграть с декораторами typescript, как указано в вопросе в декораторе метода, для этого ничего не установлено (не определено).
в приведенном ниже коде я пытаюсь создать декоратор контроллера, который создаст koa-маршрутизатор в классе контроллера. декоратор метода обернет метод и вызовет его с контекстом koa.
index.ts:
import koa, { ParameterizedContext } from "koa";
import koarouter from "koa-router";
const app = new koa();
function Controller<T extends new (...args: any[]) => {}>(path: string) {
return (controller: T) => {
const router = new koarouter({ prefix: path });
if (controller.prototype.routes) {
const routes = controller.prototype.routes;
Object.entries(routes).forEach((e) => {
if (e[0] === "GET") {
Object.entries(e[1]).forEach((r) => {
router.get(r[0], r[1]);
});
}
});
}
return class extends controller {
public router: koarouter = router;
};
};
}
function HttpGet(path: string): MethodDecorator {
// tslint:disable-next-line: only-arrow-functions
return function(
target: any,
propertyName: string | symbol,
descriptor: PropertyDescriptor,
) {
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]): any {
return originalMethod(...args);
};
if (!target.routes) {
target.routes = { GET: {}, POST: {} };
}
target.routes.GET = { ...target.routes.GET, [path]: descriptor.value };
return descriptor;
};
}
// tslint:disable-next-line: max-classes-per-file
@Controller("/adex")
class AdexController {
constructor(private msg: string = "") {
this.allAdexs = this.allAdexs.bind(this);
}
@HttpGet("/id")
public allAdexs(ctx: ParameterizedContext) {
console.log(this);
ctx.body = `hi from adex ${this.msg}`;
}
}
const adexController = new AdexController();
app.use(adexController.router.routes());
app.use(adexController.router.allowedMethods());
app.listen(3000);
tsconfig.json:
{
"exclude": ["node_modules"],
"include": ["src"],
"compilerOptions": {
/* Basic Options */
"target": "es2015" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */,
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
"declaration": true /* Generates corresponding '.d.ts' file. */,
"sourceMap": true /* Generates corresponding '.map' file. */,
"outDir": "./lib" /* Redirect output structure to the directory. */,
"rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
"strict": false /* Enable all strict type-checking options. */,
"baseUrl": "./" /* Base directory to resolve non-absolute module names. */,
"paths": {
"@/*": ["src/*"]
},
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
"experimentalDecorators": true /* Enables experimental support for ES7 decorators. */,
"emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */
}
}
Комментарии:
1. Вы должны значительно сократить код. Отрежьте ненужные вещи, чтобы нам было легче увидеть, в чем настоящая проблема.
2. я решил свою проблему, я достаточно скоро напишу подробное описание проблемы и решения.
3. @Houss_gc, каким было ваше решение? Ответьте на свой собственный вопрос ради сообщества.
Ответ №1:
проблема в моем коде — классическая эта проблема в JavaScript, я использую метод класса вне класса и пытаюсь получить к нему доступ. эта проблема не может быть решена то, что я пытался сделать, просто невозможно, для создания koa-маршрутизатора мне нужен экземпляр контроллера, и методы в этом экземпляре должны быть привязаны к этому экземпляру, что невозможно в декораторе класса или метода, при запуске кода декоратора мыу меня еще нет экземпляров. Я меняю дизайн с попытки создать маршрутизатор в декораторе, чтобы делегировать эту задачу другому классу, который будет выполнять это во время выполнения, и позволяю декораторам только аннотировать классы.
Ответ №2:
Принятый ответ на самом деле неверен. Если вы определите функцию в декораторе и назначите ее descriptor.value
, она будет привязана к this
при вызове:
export function someDecorator() {
return function (
object: Object, propertyName: string, descriptor: PropertyDescriptor
): void {
const originalFunction = descriptor.value;
descriptor.value = function () {
// here you have access to `this`:
return originalFunction.bind(this)();
};
};
}