express - TypeScript memberikan kesalahan PANJANG tentang "Tidak ada overload yang cocok untuk pemanggilan ini. Overload terakhir memberikan kesalahan berikut."
Saya sedang menulis middleware autentikasi pengguna berdasarkan boilerplate autentikasi pengguna Jason Watmore.
Hasil yang saya harapkan adalah kode ini 'langsung bekerja' karena disalin dari proyek lain di mana kode itu memang bekerja dengan tepat seperti itu.
Hasil sebenarnya adalah saya mendapatkan pesan kesalahan panjang ini:
(alias) authorize(roles?: Role[]): ({
(req: express.Request<ParamsDictionary, any, any, QueryString.ParsedQs, Record<string, any>>, res: express.Response<...>, next: express.NextFunction): Promise<...>;
unless: (options: Params) => {
...;
};
} | ((request: RequestWithUser, res: express.Response<...>, next: express.NextFunction) => Promise<...>))[]
import authorize
No overload matches this call.
The last overload gave the following error.
Argument of type '({ (req: Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: NextFunction): Promise<...>; unless: (options: Params) => { ...; }; } | ((request: RequestWithUser, res: Response<...>, next: NextFunction) => Promise<...>))[]' is not assignable to parameter of type 'RequestHandlerParams<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.
Type '({ (req: Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: NextFunction): Promise<...>; unless: (options: Params) => { ...; }; } | ((request: RequestWithUser, res: Response<...>, next: NextFunction) => Promise<...>))[]' is not assignable to type '(ErrorRequestHandler<ParamsDictionary, any, any, ParsedQs, Record<string, any>> | RequestHandler<ParamsDictionary, any, any, ParsedQs, Record<...>>)[]'.
Type '{ (req: Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: NextFunction): Promise<...>; unless: (options: Params) => { ...; }; } | ((request: RequestWithUser, res: Response<...>, next: NextFunction) => Promise<...>)' is not assignable to type 'ErrorRequestHandler<ParamsDictionary, any, any, ParsedQs, Record<string, any>> | RequestHandler<ParamsDictionary, any, any, ParsedQs, Record<...>>'.
Type '(request: RequestWithUser, res: Response, next: NextFunction) => Promise<Response<any, Record<string, any>> | undefined>' is not assignable to type 'ErrorRequestHandler<ParamsDictionary, any, any, ParsedQs, Record<string, any>> | RequestHandler<ParamsDictionary, any, any, ParsedQs, Record<...>>'.
Type '(request: RequestWithUser, res: Response, next: NextFunction) => Promise<Response<any, Record<string, any>> | undefined>' is not assignable to type 'ErrorRequestHandler<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.
Types of parameters 'res' and 'req' are incompatible.
Type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>' is missing the following properties from type 'Response<any, Record<string, any>>': status, sendStatus, links, send, and 53 more.ts(2769)
index.d.ts(163, 5): The last overload is declared here.
No quick fixes available
Berikut adalah kode yang bermasalah
function authorize(roles: Role[] = []) {
if (typeof roles === "string") {
roles = [roles];
}
return [
jwt({
secret, // authenticate JWT token and attach user to request object (req.user)
algorithms: ["HS256"],
}),
// problem is caused here with "RequestWithUser"
async (request: RequestWithUser, res: Response, next: NextFunction) => {
const acctInfo = request.auth;
if (acctInfo?.acctId === undefined) {
return res.status(401).json({ message: "Unauthorized" });
}
request.user = {
acctId: acctInfo.acctId,
role: "", // temp to satisfy ts
};
const account: Account | null = await acctDAO.getAccountById(acctInfo.acctId);
if (!account) return res.status(401).json({ message: "Unauthorized" });
const refreshTokens = await rtDAO.getAllRefreshTokensForAccount(account.acctId);
const validRoles = Object.values(Role);
const acctRole: Role = account.role as Role;
const rolesFoundOnRequest = roles.length;
if (rolesFoundOnRequest && !validRoles.includes(acctRole)) {
return res.status(401).json({ message: "Unauthorized" });
}
request.user.role = account.role;
request.user.ownsToken = (token: string) => !!refreshTokens.find((x: any) => x.token === token);
next();
},
];
}
export default authorize;
Ketika saya mengubah RequestWithUser kembali menjadi hanya Request, kesalahan itu hilang, tetapi itu tidak berhasil karena sisa middleware akan memiliki kesalahan TS tentang tipe yang salah yang diharapkan. jadi harus seperti ini.
Seperti yang bisa Anda lihat, RequestWithUser hanyalah Request Express yang diperluas:
export interface RequestWithUser extends Request {
user?: {
role: string;
ownsToken?: Function;
acctId: number;
};
auth?: {
sub: any;
acctId: number;
};
}
Saya sama sekali tidak mengerti pesan kesalahan ini. Sepertinya mengatakan "express akan meneruskan ini ke ErrorRequestHandler dan bentuknya tidak cocok" tetapi saya sama sekali tidak jelas apa yang terjadi.
edit: jadi jelas saya harus memberitahu Anda di mana kesalahan itu muncul. Rute-rute berikut semuanya adalah contoh di mana kesalahan itu muncul.
this.router.get("/", authorize([Role.Admin]), this.getAllAccounts);
this.router.get("/:id", authorize(), this.getAccountById);
this.router.post("/", authorize([Role.Admin]), createAccountSchema, this.createAccount);
this.router.put("/:id", authorize(), updateRoleSchema, this.updateAccount);
Jawaban #1
RequestWithUserhanyalahRequestExpress yang diperluas
Alih-alih membuat antarmuka khusus (bahkan jika itu memperluas Request), gunakan penggabungan deklarasi untuk meningkatkan antarmuka Request yang sebenarnya itu sendiri. Lihat misalnya Memperluas objek Request Express menggunakan Typescript
Masalahnya bukan pada kode runtime, tetapi hanya pada pengetikan tambahan.
Pesan kesalahan itu sendiri memang menyesatkan, tetapi itu disebabkan langsung oleh tipe parameter pertama yang berbeda.
Karena tidak cocok dengan tipe Request yang biasa, TypeScript mencoba menafsirkan overload fungsi yang berbeda, dan akhirnya mendapatkan satu yang seharusnya menerima campuran RequestHandler normal dan ErrorRequestHandler... tetapi fungsi Anda tidak dapat menangani keduanya, oleh karena itu muncul pesan kesalahan.
Jawaban #2
Saya mengalami kesalahan ini dan memperbaikinya dengan menambahkan : Promise<any> sebagai tipe kembalian. Kode saya yang salah adalah:
app.get(
'/',
[
// ...some middlewares
],
(req: Request, res: Response)=>{
// some code
return res.json({msg: 'ok'});
}
);
Lalu saya menambahkan tipe pengembalian ke fungsi saya:
app.get(
'/',
[
// ...some middlewares
],
(req: Request, res: Response):Promise<any>=>{
// some code
return res.json({msg: 'ok'});
}
)
Dan itu memperbaiki masalah saya setelah beberapa sakit kepala.
