컴파일러 옵션 상세 설명
target·lib·strict·module·moduleResolution·출력 관련 옵션이 검사 결과와 생성 코드, 실행 환경에 미치는 영향을 비교합니다.
9장 1절에서 tsconfig.json 파일의 중요성과 기본적인 구조를 살펴보았습니다.
이제 compilerOptions 내부에 있는 주요 옵션들을 좀 더 깊이 있게 파고들어 보겠습니다.
각 옵션이 어떤 역할을 하고, 프로젝트에 어떤 영향을 미치는지 이해하는 것은 타입스크립트 개발을 최적화하는 데 필수적입니다.
프로젝트 설정 관련 옵션
이 옵션들은 프로젝트의 전반적인 구조와 컴파일러의 파일 탐색 방식에 영향을 줍니다.
-
rootDir:string- 설명: TypeScript 소스 파일의 루트 디렉터리를 지정합니다.
outDir출력 경로는 이rootDir를 기준으로 상대 구조를 유지합니다. 예를 들어rootDir: "./src"에서src/components/button.ts를outDir: "./dist"로 컴파일하면dist/components/button.js가 생성됩니다. - 권장: 일반적으로 소스 코드가 시작되는
src폴더로 설정합니다.
- 설명: TypeScript 소스 파일의 루트 디렉터리를 지정합니다.
-
outDir:string- 설명: 컴파일된 JavaScript 파일(
.js), 타입 정의 파일(.d.ts), 소스 맵 파일(.map) 등 모든 출력 파일이 저장될 디렉터리를 지정합니다. - 권장:
dist또는build와 같이 프로젝트 빌드 결과물을 위한 전용 폴더로 설정합니다.
- 설명: 컴파일된 JavaScript 파일(
-
declaration:boolean(false가 기본값)- 설명:
true로 설정하면, TypeScript 소스 파일(.ts)과 함께 타입 정의 파일(.d.ts)을 자동으로 생성합니다. 이는 특히 라이브러리를 개발하고 배포할 때 필수적입니다. 소비하는 프로젝트가 라이브러리의 타입을 이해하는 데 이.d.ts파일이 사용됩니다. - 권장: 라이브러리 프로젝트에서
true, 애플리케이션 프로젝트에서는false또는 필요에 따라true.
- 설명:
-
sourceMap:boolean(false가 기본값)- 설명:
true로 설정하면, 컴파일된 JavaScript 파일과 원본 TypeScript 소스 파일 간의 매핑 정보를 담은 소스 맵 파일(.map)을 생성합니다. 이 파일은 브라우저 개발자 도구나 Node.js 디버거에서 컴파일된 JS 코드가 아닌 원래 TS 코드에서 직접 디버깅할 수 있게 해줍니다. - 권장: 개발 환경에서는
true, 프로덕션 빌드에서는 필요에 따라true또는false(소스 맵이 노출될 수 있으므로).
- 설명:
-
outFile:string(TypeScript 5.x 이하의 역사적 선택지, 6.0에서는 폐기 예정)- 설명: 모든 컴파일된 JavaScript 코드를 단일 파일로 합칠 때 사용합니다. 이 옵션은
module옵션이"none","system","amd"중 하나일 때만 유효합니다. CommonJS나 ES 모듈에서는 사용할 수 없습니다. - 권장: 거의 사용되지 않습니다. 현대 웹 개발에서는 웹팩 같은 번들러가 이 역할을 대신합니다.
- 설명: 모든 컴파일된 JavaScript 코드를 단일 파일로 합칠 때 사용합니다. 이 옵션은
타입 검사 관련 옵션
이 옵션들은 TypeScript 컴파일러가 코드를 얼마나 엄격하게 타입 검사할지를 제어합니다.
엄격한 검사는 초기 개발 단계에서는 번거롭게 느껴질 수 있지만, 장기적으로는 버그를 줄이고 코드의 안정성을 높이는 데 기여합니다.
strict:boolean(TypeScript 5.x의 기본값은false, 6.0의 기본값은true)- 설명:
true로 설정하면, 다음과 같은 엄격한 타입 검사 옵션 묶음을 활성화합니다. TypeScript를 사용하는 주된 이유이므로true로 설정하는 것이 강력히 권장됩니다.noImplicitAnystrictNullChecksstrictFunctionTypesstrictBindCallApplystrictPropertyInitializationnoImplicitThisuseUnknownInCatchVariables(TS 4.4+)
- 권장:
true
- 설명:
noUncheckedIndexedAccess와 exactOptionalPropertyTypes는 strict에 포함되지 않는 별도 옵션입니다. 배열·사전의 미확인 접근과 선택 속성의 부재 의미를 강화할 때 각각 설정합니다. 아래 기본값 중 일부는 strict, module 같은 다른 옵션의 영향을 받으므로 실제 설정 조합을 확인해야 합니다.
-
noImplicitAny:boolean(명시하지 않으면strict의 적용값을 따름)- 설명: 문맥에서 안전하게 추론할 타입이 없어 암시적
any로 남는 경우(예: 타입·문맥이 없는 함수 매개변수)에 오류를 발생시킵니다. 타입 표기를 생략한 모든 변수에 오류를 내는 옵션은 아닙니다.const n = 1은number로 추론되고, 초기화 없는 변수도 이후 대입과 사용 문맥에 따라 검사됩니다. - 권장:
strict: true에 포함되므로, 일반적으로 직접 설정하지 않습니다.
- 설명: 문맥에서 안전하게 추론할 타입이 없어 암시적
-
strictNullChecks:boolean(명시하지 않으면strict의 적용값을 따름)- 설명:
null과undefined값을 일반적인 다른 타입에 할당할 수 없도록 강제합니다. 즉,string | null과 같이 명시적으로null을 허용해야 합니다.null또는undefined관련 런타임 오류를 방지하는 데 매우 효과적입니다. - 권장:
strict: true에 포함되므로, 일반적으로 직접 설정하지 않습니다.
- 설명:
-
noUnusedLocals:boolean(false가 기본값)- 설명: 선언되었지만 사용되지 않는 지역 변수에 대해 오류를 발생시킵니다. 죽은 코드(dead code)를 제거하고 코드 베이스를 깔끔하게 유지하는 데 도움이 됩니다.
- 권장:
true
-
noUnusedParameters:boolean(false가 기본값)- 설명: 선언되었지만 사용되지 않는 함수 매개변수에 대해 오류를 발생시킵니다.
- 권장:
true(특히 콜백 함수의 경우, 사용하지 않는 매개변수는_로 명시하여 의도를 밝힐 수 있습니다.)
-
noImplicitReturns:boolean(false가 기본값)- 설명: 함수에서 일부 코드 경로가 값을 반환하지 않을 때 (그러나 다른 경로는 반환할 때) 오류를 발생시킵니다. 값을 반환하는 함수의 누락된 반환 경로를 검사하며, 여러 반환 타입을 유니온으로 사용하는 것 자체를 금지하지는 않습니다.
- 권장:
true
-
noFallthroughCasesInSwitch:boolean(false가 기본값)- 설명:
switch문에서 실행문이 있는case블록이break·return·throw없이 다음case로 흘러가면 오류를 발생시킵니다. 실행문이 없는 빈case여러 개로 같은 처리를 묶는 패턴은 허용합니다. - 권장:
true
- 설명:
-
forceConsistentCasingInFileNames:boolean- 설명: 동일한 파일에 대한 참조가 대소문자를 포함하여 일관되지 않을 경우 오류를 발생시킵니다. 이는 Windows/macOS(대소문자 구분 안 함)와 Linux(대소문자 구분) 간의 빌드 문제나 모듈 해결 문제를 방지합니다.
- 권장:
true
TYPE / RUNTIME / CONTRACT
strict 위에 구체적인 실패 경계의 옵션을 더한다
실패가 반복된다는 사실만으로 옵션을 정하지 않습니다. 인덱스 접근, 속성 부재, 반환 경로처럼 각 옵션이 실제로 검사할 수 있는 위험을 먼저 구별합니다.
BASELINE
strict 기준선
noImplicitAny·strictNullChecks 등의 엄격성 묶음부터 적용합니다. 모든 안전 옵션을 켜는 별칭은 아닙니다.
INDEX
미확인 배열·사전 접근
noUncheckedIndexedAccess는 미확인 접근 결과에 undefined 가능성을 더합니다. 확인 없이 값을 쓰던 경계를 찾습니다.
OPTIONAL
부재와 undefined 대입
exactOptionalPropertyTypes는 선택 속성이 없는 상태와 undefined를 대입한 상태를 구별합니다. 명시적으로 undefined를 허용할지는 속성 타입으로 정합니다.
RETURN / UNUSED
경로와 사용 여부 정책
noImplicitReturns, noUnusedLocals, noUnusedParameters는 따로 선택합니다. 이 검사로 드러나지 않는 동작·설계 문제는 테스트와 API 수정으로 검증합니다.
오류를 옵션이 검사하는 경계에 대응시키고 실제 진단을 확인합니다.
모듈 관련 옵션
이 옵션들은 TypeScript가 모듈을 어떻게 해석하고 JavaScript로 변환할지 제어합니다.
-
module:string(9장 1절 참조)- 설명: 생성될 JavaScript 코드의 모듈 형식을 지정합니다.
- 권장: Node.js 백엔드에서는
"commonjs", 프론트엔드 + 번들러 환경에서는"esnext"또는"es2020"이상. Node.js 16 이상 ES 모듈 프로젝트에서는"node16"또는"nodenext".
-
moduleResolution:string(7장 4절 참조)- 설명: TypeScript가
import문에서 모듈의 실제 파일을 찾아내는 전략을 지정합니다. - 값:
"node16","nodenext","bundler"등."node"는 과거 Node 해석 방식의 별칭이며"classic"도 레거시 방식입니다. - 선택: 현대 Node.js에서는
module과 함께node16/nodenext계열을 맞추고, 번들러에서는 그 도구와 TypeScript 버전이 지원하는bundler설정을 사용합니다.
- 설명: TypeScript가
-
baseUrl:string(7장 4절 참조)- 설명: TypeScript 5.x에서 비-상대 모듈(
import 'module-name')을 탐색하는 기준 디렉터리를 지정하던 옵션입니다. 당시에는node_modules보다 먼저 이 위치에서 찾을 수 있었습니다. TypeScript 6.0에서는 폐기 예정이며, 새 설정에서는 아래paths의 명시적 경로 매핑 등 실행 도구와 맞는 해석 규칙을 선택합니다. - 권장: 기존 5.x 프로젝트의 동작을 이해할 때 확인합니다.
paths에baseUrl이 필수인 것은 아니므로, 별칭만을 위해 새 프로젝트에 관성적으로 추가하지 않습니다.
- 설명: TypeScript 5.x에서 비-상대 모듈(
-
paths:object(7장 4절 참조)- 설명: 모듈 해석 기준에 따라 모듈 가져오기 경로에 대한 별칭(alias) 매핑을 정의합니다. 복잡한 상대 경로를 줄이고 모듈 구조를 추상화하는 데 매우 유용합니다.
- 예시:
"paths": { "@components/*": ["src/components/*"] } - 주의:
paths는 출력된 import 문자열을 바꾸지 않습니다. 실제 로더나 번들러도 같은 별칭을 해석해야 합니다.
-
esModuleInterop:boolean(TypeScript 5.x에서는module등의 설정에 따라 기본값이 달라짐) (7장 2절 참조)- 설명: CommonJS 모듈의
export와 ES 모듈의import구문 간의 상호 운용성을 향상시킵니다. 이 옵션을true로 설정하면 CommonJS 모듈의 기본 내보내기를import MyModule from 'my-module'과 같이 자연스럽게 가져올 수 있도록 컴파일러가 헬퍼 코드를 추가합니다. - 권장:
true(대부분의 현대 프로젝트에서 필요).
- 설명: CommonJS 모듈의
-
allowSyntheticDefaultImports:boolean(TypeScript 5.x에서는esModuleInterop·module·moduleResolution등의 설정에 따라 기본값이 달라짐)- 설명: 모듈이 기본 내보내기(
export default)를 하지 않더라도, 마치 기본 내보내기가 있는 것처럼import X from 'module'구문을 사용할 수 있도록 허용합니다.esModuleInterop: true를 설정하면 이 옵션도 암시적으로true가 됩니다.
- 설명: 모듈이 기본 내보내기(
JavaScript 런타임 환경 관련 옵션
-
target:string(9장 1절 참조)- 설명: 생성될 JavaScript 코드의 ECMAScript 버전을 지정합니다. 이는 어떤 JS 문법을 그대로 유지하고 어떤 문법을 하위 버전으로 트랜스파일할지 결정합니다.
- 권장: 지원해야 하는 가장 낮은 런타임 환경에 맞춥니다.
-
lib:string[](9장 1절 참조)- 설명: 컴파일 시 코드에 포함할 표준 내장 API 정의 파일 목록을 지정합니다. 예를 들어,
dom을 추가하면document,window등의 전역 객체와 관련된 타입이 제공됩니다. - 권장:
target과 함께 프로젝트가 실행될 환경에 맞게 설정합니다 (예: 브라우저 환경은dom포함).
- 설명: 컴파일 시 코드에 포함할 표준 내장 API 정의 파일 목록을 지정합니다. 예를 들어,
-
jsx:string(9장 1절 참조)- 설명: JSX 구문을 어떻게 처리할지 지정합니다.
- 값:
"preserve","react","react-jsx","react-jsxdev","react-native" - 권장: React 17+에서는
"react-jsx", 이전 버전에서는"react".
target과 lib는 런타임 API를 설치하거나 polyfill을 제공하지 않습니다. 실제 실행 환경의 지원 여부는 별도로 확인합니다.
기타 유용한 옵션
-
isolatedModules:boolean(false가 기본값)- 설명:
true로 설정하면 단일 파일 변환기가 타입 정보를 충분히 알지 못해 올바르게 처리할 수 없는 구문을 진단합니다. Babel이나 TypeScript의transpileModule처럼 파일을 하나씩 변환하는 도구의 제약을 미리 확인하는 옵션이며, 모든 스크립트를 모듈로 바꾸는 옵션은 아닙니다. 타입에만 존재하는 이름의 값 내보내기, 전역 스크립트의 namespace(.d.ts선언 파일은 제외), ambientconst enum참조 등이 제한 대상입니다. - 권장: Vite, esbuild 등 모듈별로 트랜스파일하는 번들러를 사용할 때
true.
- 설명:
-
allowJs:boolean(false가 기본값)- 설명:
true로 설정하면, TypeScript 프로그램에 JavaScript 파일(.js,.jsx)을 포함하고 출력 대상으로 삼을 수 있습니다. JavaScript의 오류 보고는checkJs또는 파일의// @ts-check로 별도 활성화합니다. - 권장: 기존 JavaScript 프로젝트를 TypeScript로 점진적으로 전환할 때 유용.
- 설명:
-
checkJs:boolean(false가 기본값)- 설명:
allowJs가true일 때, JavaScript 파일에 대해서도 TypeScript의 타입 검사를 수행합니다. JSDoc 주석을 기반으로 타입을 추론하고 오류를 보고합니다. - 권장: JavaScript 파일에 대한 타입 검사를 강화하고 싶을 때 유용.
- 설명:
-
noEmit:boolean(false가 기본값)- 설명:
true로 설정하면, 컴파일러가 JavaScript·선언·소스 맵 출력 파일을 생성하지 않고 검사만 수행합니다. 번들러(Webpack, Vite)가 트랜스파일을 담당하고 TypeScript는 타입 검사만 수행할 때 유용합니다. 다만incremental을 함께 켜면 재사용용.tsbuildinfo가 기록될 수 있습니다. 실행 산출물과 빌드 캐시는 구별합니다. - 권장: 번들러를 사용하여 최종 빌드를 수행하는 프로젝트에서
true.
- 설명:
-
incremental:boolean(false가 기본값)- 설명:
true로 설정하면, 컴파일러는 이전 컴파일의 정보를 저장하여 이후 컴파일 시 증분 컴파일을 수행합니다. 이는 컴파일 시간을 크게 단축시킵니다. - 권장: 개발 환경에서 컴파일 시간을 줄이기 위해
true.
- 설명:
tsconfig.json의 compilerOptions는 매우 많고 다양하지만, 위에 설명된 옵션들은 대부분의 타입스크립트 프로젝트에서 공통적으로 마주하고 설정해야 하는 핵심적인 부분입니다.
프로젝트의 특성과 요구사항에 맞게 이 옵션들을 정확히 이해하고 설정하는 것이 TypeScript 개발의 효율성과 안정성을 좌우합니다.
옵션을 바꿀 때는 단일 플래그의 의미보다 타입 검사, 출력, 런타임, 도구 체인이 함께 만들어내는 효과를 한 번에 검토해야 합니다.
옵션의 효과를 입력·검사·해석·출력·도구 층으로 나누어 보면 실패 지점을 좁힐 수 있습니다.
TYPE / RUNTIME / CONTRACT
옵션을 입력·검사·해석·산출·재사용 효과로 비교한다
옵션은 서로 다른 책임을 조절하며 한 옵션이 여러 책임에 영향을 줄 수도 있습니다. 실행 순서처럼 연결하지 않고, 실제 입력과 진단·산출물에서 효과를 확인합니다.
INPUT
입력 집합
files·include·exclude를 확인합니다. import graph도 입력을 늘리므로 exclude만으로 파일을 봉쇄하지 않습니다.
CHECK
타입 검사
strict는 엄격성 묶음입니다. noUncheckedIndexedAccess 같은 독립 옵션을 추가하면 허용되는 타입 관계가 달라집니다.
RESOLVE
모듈 해석
moduleResolution·paths는 타입 검사에서 import 후보를 찾습니다. module과 해석 조합을 맞추되 실제 loader의 해석도 확인합니다.
EMIT
JS·선언·맵 산출
target·module·declaration·sourceMap은 문법·모듈·선언·맵 출력을 조절합니다. noEmit이면 이 출력은 생성하지 않습니다.
REUSE / DEBUG
캐시와 디버깅
incremental은 빌드 정보를 저장해 다음 실행에서 재사용합니다. sourceMap은 산출물이면서 디버깅 도구를 잇습니다. 옵션을 단 하나의 층에만 가두지 않습니다.
선택 기준은 복사한 옵션 묶음보다 실패 지점과 관찰한 결과입니다.
기본값보다 이 프로젝트의 계약을 명시합니다. 특히 strict의 기본값은 TypeScript 6.0에서 바뀌었습니다. 엄격성 검사를 의도한다면 버전 변화에 기대기보다 strict: true를 적고, 별도 옵션은 필요한 경계에 추가합니다. 위 interop 두 옵션의 5.x 설명을 모든 버전의 기본값으로 확대하지 않습니다. TypeScript 6.0에서는 esModuleInterop: false·allowSyntheticDefaultImports: false도 폐기 예정 설정이므로, 기존 프로젝트를 옮길 때 설치 버전의 진단과 마이그레이션 안내를 확인합니다.
검사가 통과한 코드도 경계를 따로 확인합니다. 다음은 strict: true, target: "ES2020", module·moduleResolution: "Node16", types: []만 지정한 프로젝트의 src/main.ts입니다. 검사 결과를 비교할 때 각 행의 옵션 조합으로 같은 원본 코드를 새로 검사하며, 나머지 옵션은 그대로 둡니다.
export const numbers: number[] = [];
export const first: number = numbers[0];
export interface Options { timeout?: number; }
export const missing: Options = {};
export const explicitUndefined: Options = { timeout: undefined };strict만 켜면 이 코드가 모두 통과할까요? 실제 빈 배열의numbers[0]값과first: number라는 표기가 어긋날 수 있는 이유를 설명해 보세요.noUncheckedIndexedAccess만 추가,exactOptionalPropertyTypes만 추가, 두 옵션 모두 추가한 세 경우에 각각 어느 대입이 실패하나요?missing도 오류인지 구별하세요.- 빈 배열이면
first에 0을 쓰고,timeout을 지정하지 않으려는 요구사항입니다. 두 추가 옵션을 모두 켠 채 오류를 없애려면 어떻게 고치나요?numbers[0]!만 쓰는 수정이 요구사항을 만족하는지도 설명하세요.
해설
- 이 조건에서는 모두 통과합니다.
strict가 모든 위험을 검사하는 옵션은 아닙니다. 기본 배열 인덱스 접근의 타입은number지만, 실제 빈 배열에서 읽은 값은undefined입니다. 타입 표기는 실행 시 값을 바꾸지 않습니다. - 인덱스 옵션만 추가하면
numbers[0]의 타입에undefined가능성이 더해져first: number대입이 실패합니다. 선택 속성 옵션만 추가하면timeout?: number가 속성의 부재를 허용할 뿐 명시적undefined대입까지 허용하지 않아explicitUndefined가 실패합니다. 둘 다 추가하면 두 대입이 모두 실패합니다.missing = {}는 세 경우 모두 유효합니다. 명시적undefined도 요구사항이라면 속성 타입에| undefined를 적는 별도 계약을 선택할 수 있습니다. - 첫 대입은
export const first: number = numbers[0] ?? 0;으로 바꾸고, 마지막 대입은export const explicitUndefined: Options = {};로 바꿉니다. 이 경우first는 실제로 0이며 마지막 객체에는timeout키가 없습니다.!는 타입 검사에서 가능성을 지울 뿐 실행 시undefined를 0으로 바꾸지 않으므로 요구사항을 충족하지 못합니다.