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

我正在研究一个叫做expresskit的库,它允许你使用装饰器来定义routes / params / etc。 我正在重构中,我想我需要限制路线可以有的响应types。 举个例子,这里是如何创build路由 –

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

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

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

原因是,这些路线背后的逻辑越来越臃肿和纠结,以处理不同types的反应。 由于大多数路由可能是asynchronous的,我宁愿有更清洁的核心代码依靠asynchronous。 我的路线装饰器function看起来像这样 –

 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); } } 

我创build了一个通用pipe理器服务来跟踪装饰器的注册位置。 在示例中我可以得到类以及方法的名称。 我可以稍后再引用这个object[method]

在我的装饰器上,我想要求类方法是asynchronous的。 但是因为我只能得到对象和方法的名字,所以我不知道我能否做到这一点。 我怎样才能要求类方法返回Promise<any>

你需要添加一些types来指示你的装饰器工厂返回一个装饰器函数,它只接受具有期望函数签名的属性描述符(...any[]) => Promise<any> 。 我继续为它做了一个generics的别名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; } } 

演示types检查的示例用法:

 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); } } 

在操场上试试吧!