개요
CRA → Next.js 로 마이그레이션한 뒤 발생한 ESLint와 TypeScript 오류를 수정하는 첫 번째 작업입니다.
router.query 타입 문제
// workout/[uuid].tsx
//...
const {uuid} = router.query;
//TS2345: Argument of type string | string[] is not assignable to parameter of type string Type string[] is not assignable to type string
useEffect(()=>{
//...
const fetchedWorkout = await requestWorkout(uuid);
setWorkout(fetchedWorkout);
//...
},[uuid])Next.js의 router.query 값이 string | string[]인 이유는 여러 종류의 동적 라우팅을 모두 지원하기 때문입니다.
[slug](기본):/workout/123과 같은 단일 경로 값은string이 됩니다.[...slug](Catch-all Segments):/workout/a/b/c와 같은 여러 경로 값은string[](배열)이 됩니다.
문제 해결
타입 단언
// workout/[uuid].tsx
//...
const {uuid} = router.query as {uuid:string};타입 단언을 통해 uuid 의 타입을 개발자가 미리 정해줘 타입스크립트 오류를 잠재울 수 있지만 런타임에 어떤 일이 일어날지 모르니 이 방법은 사용하지 않기로 했습니다.
타입 가드
// workout/[uuid].tsx
//...
const rawUuid = router.query.uuid;
const uuid = typeof rawUuid === "string" ? rawUuid : undefined;타입 가드를 통해 uuid가 문자열이 아닌 경우, undefined 에 대입합니다.
useQuery
// workout/[uuid].tsx
//...
const {data:workout, isLoading, isError} =useQuery({
queryKey: ['workout',uuid],
queryFn: ()=>requestWorkout(uuid),
staleTime: 2*60*1000,
enabled: !!uuid
// 여기에 typeof uuid === "string" 을 해도 될 듯
});useEffect로 백엔드 서버로 부터 데이터를 받아오던 부분도 useQuery 를 이용하도록 바꿉니다. 이 때 enabled 옵션에 !!uuid 로 uuid 가 문자열 일 때만 데이터를 요청할 수 있도록 합니다.
회고
router.query값은string | string[] | undefined타입을 가질 수 있음- 타입 단언(
as { uuid: string })은 간단하지만 안전하지 않음 - 타입 가드를 통해
uuid가 문자열일 때만 사용하도록 범위를 좁히는 것이 안전한 방법 - React Query의
useQuery에enabled옵션을 적용하면,uuid가 유효할 때만 서버 요청이 실행되도록 제어할 수 있음 useQuery커스텀 훅으로 감싸서 관리 하는 것이 좋으니 나중에 수정