首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类型记录装饰器.链接方法装饰器到类装饰器

类型记录装饰器.链接方法装饰器到类装饰器
EN

Stack Overflow用户
提问于 2019-03-30 22:50:03
回答 2查看 534关注 0票数 1

我正在开发一个库,它将实现一些定制的web请求路由设置。我希望能够使用这样的类型圈装饰器来实现这个功能。

代码语言:javascript
复制
@Controller({ path: '/api' })
class TestController {
  @Route('get', '/')
  get() {
    return 'banana';
  }
}

我遇到的问题是,我似乎无法将“子”方法装饰器与“父”类装饰器连接起来。

我有一些很简单的装饰工厂,你可以在这里看到:

代码语言:javascript
复制
export function Controller(params?: IControllerParams) {
  const func: ClassDecorator = (target) => {
    registerController(target, params || {});
    logger.info(`Registered controller: ${target.name}`);
    console.dir(target); // [Function: TestController]
  };

  return func;
}

export function Route(verb: Verb, path: string) {
  const func: MethodDecorator = (target, key) => {
    registerRoute(verb, path, key, target);
    logger.info(`Registered route: ${path} for verb: ${verb}`);
    console.dir(target); // TestController {}
  };

  return func;
}

现在的问题是,每个装饰器实例化返回的目标类型都非常不同,这意味着我无法对它们进行比较。类方法返回我的类的函数签名,方法返回命名的对象签名。

我遗漏了什么吗?我见过其他库做这种链接,所以我知道这应该是可能的!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-03-31 18:13:40

我以前确实遇到过这个问题,而且有很多复杂的问题。

首先,您可能很容易失去“此”值的访问权限,因此您必须小心。另一种方法是将每个函数视为一个静态的、纯的方法,该方法恰好是在一个对象中定义的。第二个问题是对装饰者进行评估的顺序,正如您可能已经知道的那样,这个顺序是从内到外的。

考虑到这两点,我就是这么做的。我在Meteor中使用了这个代码,它做了一些与您所做的非常相似的事情。

前言

ServerModule只是一个具有一系列方法处理程序的类。也就是控制器,这个代码是为Meteor构建的。

“守则”

代码语言:javascript
复制
/**
 * This is horribly ugly code that I hate reading myself, 
 * but it is very straightforward. It defines a getter
 * property called __modulle, and returns the data that
 * we care about in a format that is readable for a future
 * registry/bootstrapping system
 */
function boltModuleProperty(proto: any) {
  Object.defineProperty(proto, '__module', {
    get: function () {
      let obj: IModuleDetails = {};
      for (let key in this.__moduleFunctions)
        obj[`${this.__moduleName}.${key}`] = this.__moduleFunctions[key];
      return obj;
    }
  })
}

/**
 * This is evaluated at the very end.
 * 
 * Collect all the methods and publications, registering
 * them with Meteor so they become available via the
 * default Meteor Methods and Subscriptions.
 */
export function ServerModule (moduleName?: string) {
  return function (target: any) {
    boltModuleProperty(target.prototype);
    // Use either a passed-in name, or the class' name
    target.prototype.__moduleName = moduleName || target.name;
  }
}


/**
 * Take the name of the method to be exposed for Meteor,
 * and save it to the object's prototype for later. We
 * we do this so we can access each method for future 
 * registration with Meteor's 'method' function
 */
export function ServerMethod (name: string = null) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    let fnName = name || descriptor.value.name;
    // ensure we actually get the real prototype
    let proto = target.prototype ? target.prototype : target.constructor.prototype 

    if (!proto.__moduleFunctions) proto.__moduleFunctions = {};
    proto.__moduleFunctions[fnName] = descriptor.value;
  }
}

解释

您正在以您能够阅读和理解的格式定义有关该类的其他信息。类中使用的每个方法/属性都需要存储有关自身的信息,而不是执行任何操作。装潢师永远不应造成任何外部的副作用。我只想说明这一点,因为您不想忘记代码库中的事情是如何发生的。

现在我们有了一些代码要看,我们必须绕开那些烦人的注册,不要失去对一些潜在绑定代码的访问。我们已经通过类上新创建的__module属性获得了所需的一切,但是它还不能通过类型记录显示。

这里有两种选择:

代码语言:javascript
复制
let myInstance: IServerModule & MyClass = new MyClass();
// or
let myInstance: any = new MyClass();

设置它

不管您访问的是方法注册(express.get,等等),您都希望有一些内容能够引用类,将其存储在注册表中(实际上只是某个引导文件中的数组,类似于角的模块),并注册该引导/模块文件中的所有内容。

访问__module属性,读取所存储的信息,并根据需要注册它。通过这种方式,您可以完成关注点的分离,您可以清楚地了解在您的应用程序中创建了什么,并且您可以在您认为必要的时候使用您的装饰器。

票数 1
EN

Stack Overflow用户

发布于 2019-03-31 11:42:22

当然,我在发帖后不久就开始处理这个问题了。我只需将“父”类目标的原型与“子”方法目标进行比较,它们就匹配了。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55436357

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档