← 전체 글로 돌아가기

TypeScript

TypeScript 타입 에러가 프로덕션에서만 나올 때

개발 환경에서는 빌드가 성공하는데 배포 환경의 TypeScript 체크에서만 실패할 때 원인을 찾는 방법을 정리했다.

TypeScript를 쓰면서 로컬에서는 완벽하게 작동하는 코드가, 배포할 때 타입 에러가 날 때가 있다. 이런 경우는 로컬과 배포 환경의 TypeScript 설정이 다르거나, 타입 정의 파일이 누락되었을 때가 많다.

타입 체크 설정 확인하기

TypeScript의 엄격함 정도는 tsconfig.json의 설정에 따라 달라진다. 로컬에서는 느슨한 설정으로 개발하고, 배포 환경에서는 엄격한 설정으로 체크할 수도 있다.

  • 먼저 볼 값: tsconfig.json의 strict, noImplicitAny 같은 옵션
  • 같이 비교할 값: 로컬과 배포 환경의 tsconfig 내용
  • 기록해둘 것: 타입 에러 메시지, 관련 파일, 타입 정의

타입 체크 수동으로 실행하기

# 현재 설정으로 타입 체크만 실행 (빌드 안 함)
npx tsc --noEmit

# 특정 파일만 체크
npx tsc --noEmit src/index.ts

# 모든 에러 출력
npx tsc --noEmit 2>&1 | head -50

nullable 체크 엄격히 하기

자주 나타나는 에러는 null 또는 undefined일 수 있는 값을 그냥 쓰는 것이다. strictNullChecks 옵션이 켜져있으면 이런 부분이 전부 에러가 된다.

// 에러: message가 undefined일 수 있음
const len = message.length

// 올바른 코드
const len = message?.length ?? 0

// 또는 타입 가드
if (message) {
  const len = message.length
}

타입 정의 파일 누락 확인하기

Third-party 라이브러리의 타입 정의 파일이 설치되지 않았을 수도 있다. @types/ 패키지가 설치되어 있는지 확인한다.

# 설치된 타입 정의 패키지 확인
npm ls | grep @types

# 누락된 타입 정의 설치
npm install --save-dev @types/node

optional chaining으로 에러 방지하기

객체의 속성에 접근할 때 ?. (optional chaining)를 쓰면, 값이 없어도 에러가 나지 않는다.

// 위험한 코드
const name = user.profile.name

// 안전한 코드
const name = user?.profile?.name ?? 'Unknown'

빌드 환경의 Node 버전과 라이브러리 버전 확인

Node 버전이나 라이브러리 버전이 다르면 타입 정의도 다를 수 있다. CI/CD 환경과 로컬의 버전을 맞춘다.

node --version
npm --version

# package-lock.json이 있으면 버전이 고정됨

타입 cast로 임시로 해결하기

타입이 명확한 경우, as 키워드로 타입을 직접 명시할 수 있다. 하지만 남용하면 타입스크립트의 이점을 잃으므로 신중하게 써야 한다.

// 에러를 무시하고 진행 (추천하지 않음)
const value = someData as string

// 더 나은 방법: 타입 체크 먼저
const value: string = typeof someData === 'string' ? someData : ''

환경별 타입 정의 분리하기

개발/배포 환경별로 다른 타입을 쓸 수도 있다. 이 경우 각 환경에 맞는 tsconfig를 만든다.

// tsconfig.dev.json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "strict": false
  }
}

TypeScript 에러는 대부분 명확한 메시지를 준다. 에러 메시지를 끝까지 읽고, 타입이 정확하게 정의되었는지 확인하면 대부분 해결된다. 그리고 배포 전에 tsc --noEmit으로 꼭 한 번 더 체크하는 습관이 중요하다.