node.js - Bagaimana Cara Membuat Error Kompilasi pada Dekorator Metode di Typescript?
Saya sedang mengerjakan sebuah pustaka yang disebut expresskit yang memungkinkan Anda menggunakan dekorator untuk mendefinisikan rute/parameter/dll untuk express. Saya sedang dalam proses refactoring dan berpikir bahwa saya perlu membatasi jenis respons yang dapat dimiliki sebuah rute. Sebagai contoh, berikut adalah cara rute dibuat sekarang-
export default class UserRouter {
@Route('GET', '/user/:userId')
public static getUser(@Param('userId') userId: number): any {
return new User();
}
}
Sebuah Route diterapkan pada metode statis. Metode statis dapat mengembalikan nilai secara langsung atau Promise. Saya ingin mewajibkan promise ke depannya seperti ini-
export default class UserRouter {
@Route('GET', '/user/:userId')
public static async getUser(@Param('userId') userId: number): Promise<User> {
return Promise.resolve(new User());
}
}
Alasannya adalah, logika di balik rute-rute ini menjadi membengkak dan kusut untuk menangani berbagai jenis respons. Karena sebagian besar rute kemungkinan bersifat asinkron, saya lebih memilih memiliki kode inti yang lebih bersih dengan mengandalkan async. Fungsi dekorator Route saya terlihat seperti ini-
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);
}
}
Saya telah membuat layanan manajer umum untuk menjaga catatan di mana dekorator terdaftar. Dalam contoh, saya bisa mendapatkan kelas serta nama metodenya. Saya bisa merujuk ini nanti seperti ini- object[method].
Pada dekorator saya, saya ingin mewajibkan bahwa metode kelas bersifat asinkron. Tetapi karena saya hanya mendapatkan objek dan nama metode, saya tidak tahu apakah saya bisa melakukan itu. Bagaimana saya bisa mewajibkan metode kelas mengembalikan Promise<any>?
Jawaban #1
Anda perlu menambahkan beberapa tipe untuk menunjukkan bahwa pabrik dekorator Anda mengembalikan fungsi dekorator yang hanya menerima deskriptor properti dengan tanda tangan fungsi yang diharapkan (...any[]) => Promise<any>. Saya telah membuat alias tipe generik RouteFunction untuk itu:
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;
}
}
Contoh penggunaan untuk menunjukkan pemeriksaan tipe:
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);
}
}
Cobalah di taman bermain!
