typescript - ไม่สามารถขยาย express request
ฉันกำลังพยายามขยายอินเทอร์เฟซ Request ของ Express ดังนี้:
import express, { Request, Response } from 'express';
interface IRequest extends Request {
user: {
id: string;
}
}
const router = express.Router();
router.get('/', auth, async (req: IRequest, res: Response) => {
try {
const user = await User.findById(req.user.id).select('-password');
res.json(user);
} catch (e) {
console.error((e as Error).message);
res.status(500).send('Server Error');
}
});
แต่ฉันได้รับข้อผิดพลาดดังต่อไปนี้:
ไม่มีการโอเวอร์โหลดที่ตรงกับการเรียกนี้ การโอเวอร์โหลด 1 จาก 3, '(path: PathParams, ...handlers: RequestHandler
[]): Router', เกิดข้อผิดพลาดดังต่อไปนี้ อาร์กิวเมนต์ประเภท '(req: IRequest, res: Response) => Promise' ไม่สามารถกำหนดให้กับพารามิเตอร์ประเภท 'RequestHandler ' ได้ ประเภทของพารามิเตอร์ 'req' และ 'req' ไม่เข้ากัน คุณสมบัติ 'user' ไม่มีในประเภท 'Request ' แต่จำเป็นในประเภท 'IRequest'. โอเวอร์โหลด 2 จาก 3, '(path: PathParams, ...handlers: RequestHandlerParams []): Router', พบข้อผิดพลาดดังนี้ ประเภทของอาร์กิวเมนต์ '(req: IRequest, res: Response) => Promise' ไม่สามารถกำหนดค่าให้กับพารามิเตอร์ประเภท 'RequestHandlerParams ' ได้ ประเภท '(req: IRequest, res: Response) => Promise' ไม่สามารถกำหนดค่าให้กับประเภท 'RequestHandler ' ได้.ts(2769)
คำตอบ #1
Typescript จะไม่ให้คุณทำ เพราะแม้ว่าคุณจะพิมพ์มันแบบนี้:
router.get('/', auth, async (req: IRequest, res: Response) => {
Typescript จะยังคงสมมติว่า express จะส่งออก Request และไม่ใช่ IRequest
อย่างไรก็ตาม เนื่องจากคุณอาจกำลังทำการ monkey-patching กับวัตถุ request คุณสามารถใช้ declaration merging เพื่อเพิ่มความสามารถให้กับวัตถุ request ภายในของ Express ได้:
https://www.typescriptlang.org/docs/handbook/declaration-merging.html
ถ้าคุณไม่ต้องการเปลี่ยนแปลงนี้ในระดับทั่วโลกกับ Request คุณก็สามารถใช้การยืนยันเพื่อให้แน่ใจว่า มันเป็น IRequest จริงๆ:
router.get('/', auth, async (req: request, res: Response) => {
try {
assertIRequest(req);
const user = await User.findById(req.user.id).select('-password');
res.json(user);
} catch (e) {
console.error((e as Error).message);
res.status(500).send('Server Error');
}
});
function assertIRequest(req: Request|IRequest): asserts req is IRequest {
if (!req?.user?.id) throw new Error('Request was not an IRequest');
}
คำตอบ #2
สมมติว่ามีการใช้อินเทอร์เฟซ IRequest สำหรับวัตถุประสงค์อื่นนอกเหนือจากข้างต้น สามารถทำตามแนวทางในบล็อกโพสต์นี้โดย Antonello Zanini: เพียงแค่ขยายอินเทอร์เฟซที่กำหนดโดย express โดยการเพิ่มไฟล์ประกาศ src/types/express/index.d.ts ด้วยเนื้อหาดังต่อไปนี้:
// src/types/express/index.d.ts
// to make the file a module and avoid the TypeScript error
export {}
declare global {
namespace Express {
export interface Request {
user: {
id: string;
}
}
}
}
เช่นเดียวกับคำตอบอื่น ๆ กลไกการรวมการประกาศของ TypeScript จะรวมการประกาศทั้งสองเข้าด้วยกันเป็นหนึ่งเดียว
หวังว่าคำตอบช้านี้จะมีประโยชน์สำหรับผู้อ่านบางคน ฉันเพิ่งมีคำถามที่คล้ายกัน
