Next.js는 Type checking 하지 않는다?

<SeongHun />·2024년 4월 25일
0

오류기록

목록 보기
3/3

1. 개요

최근 Next.js로 프로젝트를 진행하다 겪은 이슈를 공유합니다.


2. 문제 발생

개발 환경(next dev)에서 구현을 끝마치고 별다른 에러가 발생하지 않아 빌드(next build)를 시도하였습니다. 그런데 웬걸?

위 사진에서 볼 수 있듯이 타입 에러가 발생하였습니다. 내용은 다음과 같습니다.

Type error: Type 'OmitWithTag<Readonly<{ children: ReactNode; modal: ReactNode; }>, keyof LayoutProps, "default">' does not satisfy the constraint '{ [x: string]: never; }'.
Property 'modal' is incompatible with index signature.
Type 'ReactNode' is not assignable to type 'never'.
Type 'undefined' is not assignable to type 'never'.

'modal'이 인덱스 시그니처와 호환되지 않으며, 'ReactNode' 타입은 'never' 타입에 할당할 수 없다는 데요, 문제가 발생한 layout.tsx 파일의 코드를 살펴봅시다.

Next.js의 인터셉팅 라우트패러렐 라우트를 사용하기 위해서 추가해둔 LayoutProps입니다. 분명 개발 환경(next dev)에서는 타입 에러가 발생하지 않았습니다. 다시 개발 환경을 실행해 터미널을 확인해 보아도 에러가 발생하지 않습니다. 왜 이제서야, 그것도 빌드 시점에 에러가 발생한 것인지 궁금하네요. 우선, layout.tsx 파일에서는 에러를 확인할 수 없기 때문에 타입 에러가 맞는지 LayoutProps를 확인해 보기 위해 .next > types > app > layout.ts 파일을 살펴보겠습니다.

타입 에러 메시지에서 확인한 부분입니다. 빨간 줄로 에러를 표시하고 있네요. 분명 개발 환경(next dev)에서는 터미널을 살펴봐도 타입 에러가 발생하지 않았는데 말이죠.

interface LayoutProps에 modal 타입을 추가해 주니 빨간 줄로 표시해 주던 타입 에러가 사라진 것을 확인할 수 있습니다. 이제 빌드(next build) 타입 에러가 발생한 이유는 찾았습니다. 하지만 여전히 개발 환경(next dev)에서는 타입 에러가 발생하지 않다가 빌드 과정에서 타입 에러가 발생한 이유에 대해서는 의문입니다.


3. 문제 원인

이제 개발 환경에서 타입 에러가 발생하지 않는 문제 원인에 대해서 살펴보겠습니다.

Typescript next dev error reporting #14997 공유된 이슈에서 힌트를 얻을 수 있습니다. Next.js 9.4 버전에서 발생한 이슈이며 9.3.6 버전에서는 개발 환경(next dev)에서 Typscript 오류가 출력될 것을 예상할 수 있지만 9.4 버전에서는 작동하지 않는다는 내용인데요, 2020년 7월에 공유된 이슈인데 글을 작성하고 있는 현재까지(14버전) 개발 환경(next dev)에서는 타입 체킹을 지원하지 않는 것을 알 수 있겠네요.

그럼 왜 Type Checking을 하지 않는 걸까요?

3-1. Fast Refresh

9.4 버전에 추가 된 Fast Refresh 기능 때문입니다.
관련된 내용은 아래 링크에서도 확인할 수 있습니다.

Fast Refresh는 리액트 컴포넌트 수정 시 즉각적인 피드백을 제공하는 Next.js 기능입니다. 9.4 버전 이상에서는 기본적으로 활성화되어 있으며, Fast refresh를 활성화하면 컴포넌트 상태를 잃지 않고 대부분의 수정 내용을 1초 이내에 볼 수 있다고 하네요.

정리하자면, 개발 환경(next dev)에서 빠른 업데이트(즉각적인 피드백)를 위해 Next.js 9.4 버전에서 Fast Refresh 기능을 도입했으며 Fast Refresh 기능은 개발 환경에서 Type checking을 하지 않지만 빌드(next build)에서는 Type checking 하는 것으로 정리할 수 있겠네요. (Type checking is still performed during your production build.)


4. 해결책

Next.js Issues에서도 Fast refresh 기능에 대한 opt-in option을 추가해 달라는 내용이 많이 거론되었지만, Next.js에서 강력히 사용을 권장하는 핵심 기능이기 때문인지 아직까지 추가된 것은 없어 보입니다.

따라서, Issues에서 많이 공유된 대표적인 해결책을 알아보겠습니다.

4-1. "scripts" 추가

해결책에서 확인할 수 있듯이, package.json 파일의"scripts" 부분에 코드를 추가하면 됩니다.

우선 concurrently를 사용하기 위해 설치를 먼저 진행해 줍니다.

$ yarn add concurrently --dev

설치가 끝났다면 아래의 코드를 package.json 파일에 추가해 줍니다.

"scripts": {
    "dev": "concurrently -n NEXT,TS -c magenta,cyan \"next dev -p 1234\" \"yarn ts --watch\"",
    "ts": "tsc --noEmit --incremental --preserveWatchOutput --pretty"
}

저 같은 경우에는 아래와 같이 dev(next dev)와 dev-ts 명령어를 구분하여 사용하고 있습니다.

이제 concurrently 설정하신 명령어로 실행하시면 끝입니다!
저 같은 경우에는 $ yarn dev-ts 명령어를 통해 실행하면 되겠네요!


해결

명령어를 실행해 보면 빌드를 하지 않아도! 개발 환경 터미널에서! 에러를 확인할 수 있게 됩니다!🎉

오전 4:18:19 - File change detected. Starting incremental compilation...
[TS]
[TS] .next/types/app/layout.ts(28,13): error TS2344: Type 'OmitWithTag<Readonly<{ children: ReactNode; modal: ReactNode; }>, keyof LayoutProps, "default">' does not satisfy the constraint '{ [x: string]: never; }'. 
[TS]   Property 'modal' is incompatible with index signature.
[TS]     Type 'ReactNode' is not assignable to type 'never'.
[TS]       Type 'undefined' is not assignable to type 'never'.
[TS]
[TS] 오전 4:18:19 - Found 1 error. Watching for file changes.


무심코 넘어갈 수 있는 문제였지만 MJ님 덕분에 많은 고찰을 하게 되었습니다.
항상 많은 도움을 주시는 MJ님과 천만사수 분들에게 감사의 말씀을 드립니다!

p.s 틀린 내용이 있다면 알려주세요!

profile
프론트엔드 개발자..? 쉽지 않겠는걸.. 그치만 재밌는데? 좋아~ 가보자구!

0개의 댓글