JavaScript에서 TypeScript로 전환하기 (NextJS)

Sep 12, 2023
JavaScript에서 TypeScript로 전환하기 (NextJS)
 
안녕하세요. MyDATA에서 프론트엔드 개발하고있는 JT입니다.
이번 포스팅에서는 Next.js 프레임워크를 기반으로 한 JavaScript 프로젝트를 TypeScript로 전환하는 경험을 공유하려 합니다. TypeScript의 장점과 전환 가능성을 살펴보기 위해, 작은 사이드 프로젝를 전환해 보았고, 그 과정에서의 경험과 고민들을 중심으로 본문을 진행하겠습니다.
 
 

1. 왜 TypeScript를 사용해야 하는가?

2012년 마이크로소프트가 발표한 TypeScript는 JavaScript를 기반으로 정적 타입 문법을 추가한 프로그래밍 언어입니다.
최근 몇 년간 사용률이 계속해서 증가하고 있고, 2023 stack overflow 설문조사에 따르면 admired부분에서 70% 이상을 기록하며, TypeScrtipt를 계속 사용하고 싶어 하는 개발자가 많은 것으로 알 수 있습니다.
그러면 왜 개발자들은 TypeScript를 선호하며, 우리는 언제 JavaScript대신 TypeScript써야 하는 걸까요?
 

1-1. 사전 오류 발견

typescript의 정적 타입 검사를 통해 코드를 실행하기 전에 타입 관련 오류를 사전에 발견하고 수정할 수 있습니다. 이는 디버깅 시간을 줄여주며, 런타임에서의 예기치 않은 오류 발생을 방지합니다.
예를 들어, 수를 더하기 위한 sum() 함수를 작성할때
// math.js function sum(a, b) { return a + b; } sum(10, 20); // 30 sum('10', '20'); // 1020
javascript일때는 매개변수로 숫자가 아닌 값이 들어왔을 때 의도와 다르게 나옵니다.
// math.ts function sum(a: number, b: number) { return a + b; } sum('10', '20'); // Error
typescript를 사용하면 IDE에서 타입 관련 오류를 실시간으로 확인할 수 있으며, 디버깅 과정에서도 잠재적인 문제점을 미리 인지하고 수정할 수 있습니다.
notion image
notion image
 
 

1-2. 코드의 명확한 의도 전달

typescript의 정적 타입 검사는 코드의 의도를 분명히 하여, 개발자 간의 오해를 줄일 수 있습니다. 특히 대규모 프로젝트에서 팀원들 사이의 명확한 커뮤니케이션은 코드의 품질과 개발 속도에 큰 영향을 미칩니다. 타입스크립트를 사용하면, 함수나 변수의 목적과 그 사용 방법이 타입을 통해 분명해질 뿐만 아니 코드를 더욱 쉽게 이해하고, 오류 없이 활용할 수 있게 됩니다.
위의 예시에서 사용했던 sum()함수의 반환 값을 number로 명시함으로써, 해당 함수가 숫자 값을 반환한다는 것을 명확히 알 수 있습니다. 이는 다른 개발자들이 해당 함수를 사용할 때 어떤 형태의 값을 기대해야 하는지 확실히 알려줍니다.
notion image
 
또한, 대부분의 IDE에서 정적 타입 검사를 지원하므로, 개발자가 코드를 작성하는 도중 잘못된 타입의 값이 사용될 경우 즉각적인 피드백을 받을 수 있습니다. 이는 실수를 줄이고, 코드의 품질을 높이는 데 큰 도움이 됩니다.
 

2. TypeScript 전환

 
전환하려는 프로젝트는 JavaScript를 사용한 Next.js 기반의 프로젝트입니다. 해당 프로젝트의 JavaScript를 TypeScript로 전환하는 과정에 대해 간략하게 나열하겠습니다.

2-1. TypeScript 관련된 패키지 및 외부 라이브러리 설치

npm install --save typescript @types/react @types/node
다음 명령어를 통해 typescript, React타입 정의 패키지와 Node.js 타입 지원 패키지를 설치해야 합니다.
그리고 사용중인 외부 라이브러리가 있다면 TypeScript를 지원하는지 확인하고, 해당 라이브러리의 타입 정의를 @types/{library-name} 형태로 설치해야 할 수도 있습니다.

2-2. TypeScript 설정 파일 생성

NextJS 공식문서에 타입스크립트 설정을 참고하여 실행하시면 됩니다.
touch tsconfig.json
tsconfig.json 파일을 만들고,
npm run dev
명령어를 실행하면 tsconfig.json 파일에 기본 내용이 작성됩니다.
 

2-3. 파일 확장자 변경

NextJS프로젝트에서 JavaScript로 작성할 때 주로 JSX 파일 내의 컴포넌트로 구성됩니다. JSX(JavaScript XML)는 React의 UI 컴포넌트를 표현하기 위한 문법 확장입니다. 이를 사용하면 JavaScript 내에서 UI 컴포넌트를 HTML과 유사한 문법으로 작성할 수 있습니다. NextJS에서 JavaScript를 TypeScript로 전환은 JS파일과 JSX파일을 각각 TS와 TSX로 변경하면서 내부의 타입을 정의하는 작업이 필요합니다.
 
notion image
notion image
다음과 같이 확장자를 변경했다면, 내부에 타입이 정의되지 않은 변수나 함수 반환값에 대한 설정해줘야 합니다.
// tsconfig.json { ... "allowJs": true, ...
tsconfig 설정의 이 옵션은 TypeScript 컴파일러가 JavaScript 파일을 처리할 수 있게 하므로, 기존 JS 코드와 함께 TS 코드를 점진적으로 도입할 수 있습니다.
 

2-4. 타입 설정

  1. 변수, 상수의 타입을 정의해줘야합니다.
    1. // post.jsx const [perPage, setPerPage] = useState(5); const [page, setPage] = useState(1); const [search, setSearch] = useState(''); const [accessToken, setAccessToken] = useRecoilState(accessTokenState) const [refreshToken, setRefreshToken] = useRecoilState(refreshTokenState)
      // post.tsx const [perPage, setPerPage] = useState<number>(5); const [page, setPage] = useState<number>(1); const [search, setSearch] = useState<string>(''); const [accessToken, setAccessToken] = useRecoilState<string>(accessTokenState) const [refreshToken, setRefreshToken] = useRecoilState<string>(refreshTokenState)
 

2-5. 커스텀 타입 및 인터페이스 작성

  1. 커스텀 타입
    1. TypeScript에서는 type이라는 키워드로 사용자 정의 유형을 생성할 수 있습니다.
      // write.jsx const [post, setPost] = useState({ title: '', content: '', boardId: 0 });
      // write.tsx type WritePost = { title: string; content: string; boardId: number; } const [post, setPost] = useState<WritePost>({ title: '', content: '', boardId: 1 });
      위와 같이 useState훅에 제네릭 타입을 전달하여 사용할 수 있습니다. 이렇게 타입을 명시적으로 정의함으로써 코드의 안정성을 높이고, 대규모 프로젝트나 여러 팀원과의 협업에 있어 중요한 역할을 합니다. 제네릭을 활용하여 post 변수에 WritePost 타입을 지정하면, 잘못된 타입의 할당 시 TypeScript 컴파일러가 오류를 표시합니다. 이를 통해 오류 가능성을 대폭 줄일 수 있습니다.
       
  1. 인터페이스 작성
    1. 인터페이스는 객체의 구조를 정의하는 데 사용되는 강력한 도구입니다. 예를 들어, 사용자 정보를 나타내는 인터페이스를 다음과 같이 작성할 수 있습니다.
      // interfaces.tsx export default interface ILoginReq { loginId: string; loginPw: string; } export default interface IResponseData { accessToken: string; refreshToken: string; userId: string; accessTokenExpiresAt: string; refreshTokenExpiresAt: string; }
      인터페이스를 사용하면 타입의 객체를 생성할 때 각 필드의 타입을 준수해야 합니다.
 
커스텀 타입과 인터페이스를 활용하면 코드의 구조와 의도를 명확하게 나타낼 수 있습니다. 또한, 이를 통해 코드의 오류를 줄이고 팀원 간의 협업 효율을 높일 수 있습니다.
 

3. 총평

TypeScript는 코드의 안정성을 높여 줄 뿐만 아니라, 코드의 의도를 명확하게 전달하면서도 확장성과 유지 보수성을 크게 향상시키고, 특히 Next.js와 TypeScript의 조합은 매우 유용했습니다. Next.js는 타입스크립트의 통합을 원활하게 지원하므로, 프로젝트를 TypeScript로 전환하는 데 큰 어려움이 없었습니다.
물론 도입 초기에는 학습 곡선이나 라이브러리 호환성 문제 등 몇몇 단점도 고려해야 합니다. 하지만 장기적으로 볼 때 이러한 투자는 큰 가치를 가져올 것으로 생각했습니다.
또한, TypeScript를 점층적으로 적용하는 방법은 프로젝트 전체를 한 번에 변경하는 부담을 줄여줬습니다. allowJs 설정을 통해 기존 JavaScript 코드와 TypeScript 코드를 동시에 유지할 수 있는 것은 전환 과정을 훨씬 수월하게 만들어줬습니다.
TypeScript는 프로젝트의 품질 향상과 팀 생산성 증가에 기여하는 좋은 선택이 될 거라 생각합니다.
 
 
[레퍼런스]
타입스크립트 핸드북 - https://joshua1988.github.io/ts/ TypeScript vs JavaScript - https://www.guru99.com/typescript-vs-javascript.html
 
Share article

More articles

See more posts
RSSPowered by inblog