전체적으로 리펙토링을 하면서 보낸 더딘 한 주였으며, 근본적인 문제 원인을 빠르게 캐치하지 못하여 시간을 많이 허비한 한 주 였다. 덤으로 이력서 작성과 아르바이트를 진행하게 되어 많은 시간을 할애하지 못하였다.
그래 이게 다 거짓말이었으면 좋겟다..
Nest
만 사용하던 나에게 찾아온 Express
.. 더구나 한 번도 안 써본 TypeScript
+ Express
조합이라 생각도 못했던 에러를 마추쳤다.
Error-handling middleware
에서 인자는 꼭 4개여야하는 것도 까먹어 버릴 만큼 사용하지 않았던 8개월은 길었나보다. 코딩 중 나를 괴롭힌 문제를 정리해 보겠다!
오류 상황: router에서 호출 오버로드 오류 방생
발생 배경: 인증 미들웨어 작성 중 유효성 검사에 return을 입력하니 생김
오류 코드: typescript 2769
오류 메시지:
이 호출과 일치하는 오버로드가 없습니다.
마지막 오버로드에서 다음 오류가 발생했습니다.
'(req: Request, res: Response, next: NextFunction) => Promise<Response<any, Record<string, any>> | undefined>' 형식의 인수는 'RequestHandlerParams<ParamsDictionary, any, any, ParsedQs, Record<string, any>>' 형식의 매개 변수에 할당될 수 없습니다.
'(req: Request, res: Response, next: NextFunction) => Promise<Response<any, Record<string, any>> | undefined>' 형식은 'RequestHandler<ParamsDictionary, any, any, ParsedQs, Record<string, any>>' 형식에 할당할 수 없습니다.
'Promise<Response<any, Record<string, any>> | undefined>' 형식은 'void | Promise<void>' 형식에 할당할 수 없습니다.
'Promise<Response<any, Record<string, any>> | undefined>' 형식은 'Promise<void>' 형식에 할당할 수 없습니다.
'Response<any, Record<string, any>> | undefined' 형식은 'void' 형식에 할당할 수 없습니다.
'Response<any, Record<string, any>>' 형식은 'void' 형식에 할당할 수 없습니다.
관련 로그:
[{
"resource": "/Users/choi/Desktop/velog-dashboard/src/routes/user.router.ts",
"owner": "typescript",
"code": "2769",
"severity": 8,
"message": "이 호출과 일치하는 오버로드가 없습니다.\n 마지막 오버로드에서 다음 오류가 발생했습니다.\n '(req: Request, res: Response, next: NextFunction) => Promise<Response<any, Record<string, any>> | undefined>' 형식의 인수는 'RequestHandlerParams<ParamsDictionary, any, any, ParsedQs, Record<string, any>>' 형식의 매개 변수에 할당될 수 없습니다.\n '(req: Request, res: Response, next: NextFunction) => Promise<Response<any, Record<string, any>> | undefined>' 형식은 'RequestHandler<ParamsDictionary, any, any, ParsedQs, Record<string, any>>' 형식에 할당할 수 없습니다.\n 'Promise<Response<any, Record<string, any>> | undefined>' 형식은 'void | Promise<void>' 형식에 할당할 수 없습니다.\n 'Promise<Response<any, Record<string, any>> | undefined>' 형식은 'Promise<void>' 형식에 할당할 수 없습니다.\n 'Response<any, Record<string, any>> | undefined' 형식은 'void' 형식에 할당할 수 없습니다.\n 'Response<any, Record<string, any>>' 형식은 'void' 형식에 할당할 수 없습니다.",
"source": "ts",
"startLineNumber": 19,
"startColumn": 23,
"endLineNumber": 19,
"endColumn": 43,
"relatedInformation": [
{
"startLineNumber": 153,
"startColumn": 5,
"endLineNumber": 163,
"endColumn": 10,
"message": "여기서 마지막 오버로드가 선언됩니다.",
"resource": "/Users/choi/Desktop/velog-dashboard/node_modules/.pnpm/@types+express-serve-static-core@5.0.1/node_modules/@types/express-serve-static-core/index.d.ts"
}
]
}]
오류 원인: Express의 RequestHandler는 void | Promise<void>
반환 타입을 요구하는 반면 현재 코드는 Response객체 반환 중이라 타입 에러가 남 (return res.status().json({message: ''})
에러 로그 해석: typescript가 owner인 점을 확인하여 typescrpit + express 조합에서 생긴 에러이며 @types/express-serve-static-core/index.d.ts에서 발생하였음
해결 방법: return문 제거 or as RequestHandler 로 타입 단언해주기
코드 예시:
if (!accessToken || !refreshToken) {
res.status(401).json({ message: 'accessToken과 refreshToken의 입력이 올바르지 않습니다' });
- return
}
2.as RequestHandler 로 타입 단언 : 타입 안정성 유지할 수 있으나 타입 단언은 TypeScript의 타입 체크를 우회 할 수 있다.
export const validateResponse = <T extends object>(dtoClass: new (...args: any) => T) => {
return (...) + as RequestHandler;
🤔 두 가지 장점을 다 살린다면 이렇게 작성하면 될까? 이것또한 내일!
const validateToken: RequestHandler = (req, res, next) => {
if (!accessToken || !refreshToken) {
res.status(401).json({ message: '토큰이 올바르지 않습니다' });
return next(new TokenError('Invalid tokens'));
}
...
next();
};
참고 자료: DefinitelyTyped Github , Express Middleware 공식문서
목요일 부터는 꽤 널널하니 진짜 꼮 빡집중해서 다 해벌인다.
GPT한테 받는 첨삭이라.. 뭔가 애가 쓸만은 한데 주변 환경이나 배경을 정말 대략적으로만 알려주다 보니까 이상한 코드를 주는 경우가 많더군요;
어떻게 잘 쓰면 정말 유용한 친구긴 합니다! 저도 커스텀 오류 핸들링 적용할 때 애용해서 썼답니다~
아무튼 지금 있는 Problem들 다 잘 해결하고, 크리스마스 전까지 열심히 달려봅시다!
"내배캠 Express 강의 복기" 가 인상깊은데요 ㅋㅋㅋㅋ
"목요일 부터는 꽤 널널하니 진짜 꼮 빡집중해서 다 해벌인다." 가 글로 안끝나면 정말 멋있을 것 같아요! 화이팅! 연말 전 까지 무조건! 무조건!! 아자아자!