[Typescript] useParams() 타입 & undefined 에러

1

TYPESCRIPT

목록 보기
7/8
post-thumbnail

혹시나 잘못된 개념 전달이 있다면 댓글 부탁드립니다. 저의 성장의 도움이 됩니다.

문제상황

TS2345: Argument of type 'string I undefined' is not assignable to parameter of type 'string'.
Type 'undefined' is not assignable to type 'string'.

Javascript와 달리 Typescript를 사용할 때, 공식문서에 정의된 방식으로 사용하면 타입에 undefined를 포함하게 된다. 그래서 useEffect에서 fetch 요청을 위해 useParams의 반환값을 전달하면 타입 에러가 발생한다.
undefined이 아닌 경우에 fetch 요청이 수행되도록, if (recipeId) { /*fetch 요청 */ } 를 추가해서 해결할 수도 있겠지만 다른 방법이 있을 것 같아 구글링을 했다.

const { recipeId } = useParams();

useEffect(() => {
	dispatch(fetchRecipeEditData(recipeId)); // <------ 에러 발생
}, []);


해결 X : 제네릭 추가

구글링할 때 가장 많이 나온 방법이 useParams에 제네릭을 추가하는 방법이 있었다. 하지만 아래 사진처럼 타입을 명시해도 여전히 undefined를 포함했다.

// 이 방법도 동일하게 undefined 포함
type recipeParams = {
  recipeId: string;
};

const { recipeId } = useParams<recipeParams>();

react-router-dom v6 이상부터 제네릭 미지원

I'm not sure this makes sense from a practical perspective. We're not using this State generic internally for the React Context value, so this is really just forcing the type to have the generic on it. You could do the same thing with useLocation() as Location<MyState>, without changing this API. I'd rather not encourage type overrides if we can avoid it, so I'm going to close this out.
react-router의 Github

위 설명은 useLocation에 대한 내용이지만 제네릭 미지원은 동일한 듯 하다. useParam에 대한 이슈가 장황하게 설명되어있는데 필자는 영어를 못한다...
다행히 다른 이슈 [Feature]: Typesafe useParam 에 react-router의 권위자?(인용구 말한 개발자)가 직접 링크를 걸어서 해결책을 알려주었다.

하지만 이 방법으로 사용해도 값이 있다고 명시해줄 뿐 문자열로 제한하지는 않는다.


의문점

  • useParams() 을 사용하면 타입추론으로 string | undefined 가 반환(v6부터 해당)

undefined가 언제 사용되는가 아래 조건문을 추가했다. 하지만 메인페이지에서 해당 컴포넌트로 이동할때까지 "언제나옴" 문구는 찾아볼 수 없었다.
실행컨텍스트 초기화 단계 때문인건가?

if (!recipeId) {
  console.log("언제나옴");
}
// recipeId가 undefined일 때 출력되야하지만 console에서 출력되지는 않는다.

권위자가 useLocation() as Location<MyState> 방법을 알려줘도 이걸 useParam에서 적용하기가 어렵다. Location 저 자리에 대체될 값을 모르겠다.

혹시나 이 방법을 적용할 해결방법을 찾으신 분 댓글 부탁드립니다.


해결 : type assersion

/*------- 실패 -------*/
// const { recipeId } = useParams<"recipeId">();
// const { recipeId } = useParams();


/*------- 성공 -------*/
const { recipeId } = useParams() as { recipeId: string };
// const { recipeId } = useParams() as any; 
// any인데도 fetch 요청값에 에러가 발생하지 않았다. any보다 객체 타입을 명시해줬다.

위 섹션의 주석처리한 방법 모두 실패했다.
최후의 수단으로 type assersion으로 string 타입을 명시했다.
(interface나 type alias 방법으로 따로 명시해주는 것도 가능하다)

cf. 훅으로 만드는 방법에 대한 블로그이다.
useRequiredParams - a Hook for Required Route Parameters with React-Router v6 in TypeScript



TIL

비교하는 것보다 해결되면 넘기는게 더 좋은 방법일까하는 생각을 했다...
문제가 발생하면 되도록 공식문서에서 찾아서 해결책을 찾으려고하는데, 명확한 출처를 찾기 어려운 정보들이 많고, 공식문서에도 없는 경우가 많아서 알아보는데 꽤나 시간을 사용했다.
if(!recipeID){ } 방법으로 쉽게 해결하는게 더 나았을 것 같기도하다. 굳이 어려운 길을 돌아가는... 게다가 블로깅을 하면서도 명확한 출처를 찾기 어려워 찜찜하다.

하지만, 덕분에 타입스크립트의 Non-null assertion operator 라는 것을 접했다.
물론 이번에 이 방법으로도 해결되지 않았다.
자바스크립트의 ? '있다면~' 이라는 것처럼 타입스크립트에서의 ! 은 null이나 undefined가 아니라는 의미다.
?와 비슷한 방식으로 사용되는 건가? 직접 사용해보진 않아서 이런게 있구나하고 넘겼지만, 타입스크립트도 프로젝트하면서 그때그때 필요한 개념을 찾았던거라 한번 훑어 봐야겠다.

0개의 댓글