如何在 Typescript 中的方法装饰器上创建编译错误?

mic*_*cah 3 node.js typescript

我正在开发一个名为expresskit的库,它允许您使用装饰器来定义express的路线/参数/等。我正在重构,我认为我需要限制路由可以具有的响应类型。作为示例,以下是现在创建路由的方式 -

export default class UserRouter {
  @Route('GET', '/user/:userId')
  public static getUser(@Param('userId') userId: number): any {
    return new User();
  }
}
Run Code Online (Sandbox Code Playgroud)

路由应用于静态方法。静态方法可以直接返回一个值,也可以返回一个Promise. 我想要求这样的承诺-

export default class UserRouter {
  @Route('GET', '/user/:userId')
  public static async getUser(@Param('userId') userId: number): Promise<User> {
    return Promise.resolve(new User());
  }
}
Run Code Online (Sandbox Code Playgroud)

原因是,这些路由背后的逻辑变得臃肿和混乱,无法处理不同类型的响应。由于大多数路由可能是异步的,因此我宁愿通过依赖异步来获得更清晰的核心代码。我的路线装饰器功能如下所示-

export default function Route(routeMethod: RouteMethod,
                              path: string) {                       
  return function(object: any, method: string) {
    let config: IRouteConfig = {
      name: 'Route',
      routeMethod: routeMethod,
      path: path
    };

    DecoratorManager.registerMethodDecorator(object, method, config);
  } 
}
Run Code Online (Sandbox Code Playgroud)

我创建了一个通用管理器服务来跟踪装饰器的注册位置。在示例中,我可以获得类和方法名称。我可以稍后像这样引用它object[method]- 。

在我的装饰器上,我想要求类方法是异步的。但由于我只获得对象和方法名称,我不知道是否可以做到这一点。我如何要求类方法返回Promise<any>

Mat*_*ens 5

您需要添加一些类型来指示您的装饰器工厂返回一个装饰器函数,该函数仅接受具有预期函数签名的属性描述符(...any[]) => Promise<any>。我继续RouteFunction为它创建了一个通用类型别名:

type RouteMethod = 'GET' | 'POST'; // or whatever your library supports

// The function types the decorator accepts
// Note: if needed, you can restrict the argument types as well!
type RouteFunction<T> = (...args: any[]) => Promise<T>;

// The decorator type that the factory produces
type RouteDecorator<T> = (
    object: Object,
    method: string,
    desc: TypedPropertyDescriptor<RouteFunction<T>> // <<< Magic!
) => TypedPropertyDescriptor<RouteFunction<T>>

// Decorator factory implementation
function Route<T>(routeMethod: RouteMethod, path: string) : RouteDecorator<T> {                       
  return (object, method, desc) => {
    // Actual route registration goes here
    return desc;
  } 
}
Run Code Online (Sandbox Code Playgroud)

演示类型检查的示例用法:

class RouteExample {

    @Route('GET', 'test1') // works, return type is a Promise
    test1(): Promise<number> {
        return Promise.resolve(1);
    }

    @Route('GET', 'test2') // error, return type not a Promise
    test2(): number {
        return 2;
    }

    @Route('GET', 'test3') // error, property is a number rather than a function
    get test3(): Promise<number> {
        return Promise.resolve(3);
    }

}
Run Code Online (Sandbox Code Playgroud)

去游乐场试试吧!