노트tsc --noEmit과 타입 검사 분리
noEmit
프론트엔드#ts#tooling · 연결된 개념 5개
쉽게 말하면
tsc --noEmit은 원고를 맞춤법 검사만 하고 인쇄는 하지 않게 하는 옵션이에요. 인쇄는 Vite 같은 빠른 도구에 맡기는데, 그 도구들은 타입을 검사하지 않으니 검사만 따로 돌리는 거죠.
비유의 한계 인쇄를 안 한다고 검사가 빨라지진 않아요. 검사 비용은 그대로라 incremental이나 watch로 줄이고, 테스트 러너도 타입을 안 보니 CI나 테스트 스크립트에 따로 넣어야 해요.
--noEmit은 tsc에게 타입 검사만 하고 JavaScript 파일은 만들지 말라고 하는 옵션이다. 오류가 있으면 0이 아닌 종료 코드로 실패하고, 없으면 조용히 끝난다.
- 왜 필요한가: Vite, esbuild, SWC(Speedy Web Compiler), Babel, Vitest 같은 요즘 도구는 TS의 타입 표기를 지우기만 하고 검사하지 않는다. 그래서 타입 오류가 있어도 개발 서버, 빌드, 테스트가 그대로 돌아간다
- 그래서 역할을 나눈다. 산출물은 번들러가 만들고,
tsc는 검사기로만 쓴다. tsconfig.json에 "noEmit": true를 두는 템플릿이 많다
- 흔한 함정: 테스트는 통과했는데
build 스크립트(tsc --noEmit && vite build)에서만 실패하는 경우다. 테스트 러너도 타입을 안 보기 때문이다. 테스트 스크립트 앞에 tsc --noEmit을 붙이거나 CI(Continuous Integration)에서 따로 돌려 간극을 없앤다
- 검사 범위는 tsconfig의
include가 정한다. 테스트 파일도 포함되면 함께 검사된다
import './a.ts'처럼 확장자를 쓰게 해 주는 allowImportingTsExtensions는 noEmit(또는 emitDeclarationOnly)일 때만 켤 수 있다. JS를 내보내지 않으니 경로를 고칠 일이 없기 때문이다
- 파일을 안 쓸 뿐 검사 비용은 그대로다. 자주 돌린다면
--incremental이나 --watch로 줄인다
파일 단위 변환 도구와 맞추기 위한 다른 옵션은 verbatimModuleSyntax와 import type, 전체 옵션은 tsconfig 핵심 옵션. CI에 넣는 방법은 GitLab CI/CD 파이프라인 같은 파이프라인 노트 참고.
연결된 개념
이 노트를 가리키는 문서
뜻이 가까운 노트
- Nx
Nx는 캐싱과 병렬 실행에 더해 프로젝트 그래프, 코드 생성, 아키텍처 규칙 강제까지 제공하는 모노레포 플랫폼이다. "빠른 실행 한 가지"에 집중하는 turborepo와 달리 기능을 두루 갖춘 쪽을 지향한다.
- Turborepo
Turborepo는 JavaScript·TypeScript 모노레포의 태스크(빌드·린트·테스트)를 빠르게 돌리는 빌드 시스템이다. 기존 package.json 스크립트는 그대로 두고, 스크립트 사이의 의존 관계만 알려 주면 병렬 실행과 캐싱을 맡는다. 의도적으로 "빠른 실행과 캐시" 한 가지에 집중한다.
- 타입 좁히기와 타입 가드
타입 좁히기(Narrowing)는 선언된 넓은 타입(유니언, unknown)을 실행 경로를 따라 더 구체적인 타입으로 줄여 가는 과정이다. 그 근거가 되는 런타임 검사를 타입 가드(Type Guard)라고 한다.
- 타입 추론과 타입 검사
타입 추론(Type Inference)은 표기가 없어도 컴파일러가 값의 타입을 정하는 단계이고, 타입 검사(Type Checking)는 정해진(추론됐거나 명시된) 타입을 코드가 지키는지 확인하는 단계다. 보통 추론이 먼저 일어나고, 그 결과를 기준으로 검사한다.
- 템플릿 리터럴 타입
템플릿 리터럴 타입(Template Literal Types)은 문자열 리터럴 타입을 템플릿 문자열 문법으로 조합해 새 문자열 유니언을 만드는 기능이다. 유니언을 넣으면 가능한 모든 조합이 나온다.