tsconfig.json은 TypeScript 프로젝트의 설정 파일입니다. 인수 없이 tsc를 실행하면 컴파일러는 현재 폴더에서(없으면 상위 폴더에서) 이 파일을 찾고, compilerOptions의 옵션을 읽고, include에 나열된 파일을 검사합니다. 작지만 완전한 예입니다.
{
"compilerOptions": {
"target": "es2022",
"module": "nodenext",
"strict": true,
"rootDir": "./src",
"outDir": "./dist"
},
"include": ["src"]
}
이 설정은 src의 모든 TypeScript 파일을 Node.js의 모듈 규칙에 따라 ES2022 코드로 dist에 컴파일하고, 모든 strict 검사를 켭니다. npx tsc --init은 모든 옵션에 주석이 달린 더 긴 시작 파일을 생성합니다.
이 파일은 주석이 허용된 JSON입니다. // 주석, /* */ 주석, 끝의 쉼표를 모두 받아들입니다.
권장 시작 설정
Node.js 애플리케이션이나 스크립트라면:
{
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist",
"target": "es2024",
"lib": ["es2024"],
"module": "nodenext",
"types": ["node"],
"strict": true,
"noUncheckedIndexedAccess": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true,
"sourceMap": true
},
"include": ["src"]
}
Node.js 타입을 위해 npm install --save-dev @types/node가 필요합니다. module: "nodenext"에서는 package.json의 "type" 필드가 .ts 파일이 ES 모듈("type": "module")인지 CommonJS("type": "commonjs", npm init -y가 쓰는 값)인지 정합니다. import와 export를 쓰는 새 프로젝트에는 "type": "module"을 쓰세요.
Vite, esbuild, webpack 같은 번들러가 빌드하는 코드라면 JavaScript는 번들러가 쓰고 tsc는 검사만 합니다.
{
"compilerOptions": {
"target": "es2022",
"lib": ["es2022", "dom"],
"module": "preserve",
"noEmit": true,
"strict": true,
"noUncheckedIndexedAccess": true,
"verbatimModuleSyntax": true,
"isolatedModules": true,
"skipLibCheck": true,
"jsx": "react-jsx"
},
"include": ["src"]
}
프레임워크 스타터(Vite, Next.js, Angular)는 자체 tsconfig.json을 생성합니다. 그것을 바꾸기보다는 그것에서 시작하세요.
중요한 옵션
| 옵션 | 하는 일 | TypeScript 7 기본값 |
|---|---|---|
target | 출력의 JavaScript 버전. 오래된 target에서는 최신 문법을 다시 씀 | es2025 |
lib | 검사기가 아는 내장 API 타입(Array.prototype.at, Map, document) | target에 맞춤, DOM 포함 |
module | 출력하는 모듈 코드의 종류와 적용되는 모듈 규칙 | esnext |
moduleResolution | 디스크에서 import 경로를 찾는 방법 | 짝이 되는 module이면 nodenext나 node16, 아니면 bundler |
strict | strict 검사 전체를 켬 | true |
rootDir | 폴더 구조를 outDir에 그대로 옮길 기준 폴더 | tsconfig.json이 있는 폴더 |
outDir | .js(와 .d.ts) 파일이 가는 곳 | 각 소스 파일 옆 |
include / exclude / files | 프로젝트에 속하는 파일 | 폴더 아래 모든 .ts 파일 |
types | import 없이 불러올 @types 패키지 | [], 없음 |
noEmit | 검사만 하고 아무것도 쓰지 않음 | false |
declaration | .d.ts 타입 선언 파일도 씀 | false |
sourceMap | 디버거용 .js.map 파일을 씀 | false |
esModuleInterop | CommonJS 패키지에서 import x from "cjs-package"가 동작하게 함 | true(끌 수 없음) |
skipLibCheck | node_modules의 것을 포함해 .d.ts 파일의 타입 검사를 건너뜀 | false |
target과 lib
target은 출력이 어떤 JavaScript 버전에서 실행되어야 하는지 정합니다. target보다 새로운 문법은 다시 쓰입니다. "target": "es2017"이면 클래스 필드나 ??=가 오래된 코드로 바뀝니다. TypeScript 7이 받아들이는 가장 낮은 target은 es2015(es6)이고, es5는 제거되었습니다.
target은 빠진 런타임 API를 추가하지 않습니다. 그것을 기술하는 것은 lib의 일이고, 채우는 것은 폴리필의 일입니다. lib는 어떤 내장 객체와 메서드가 존재하는지 검사기에 알려 줍니다. 기본값은 target을 따르며 브라우저 DOM 타입도 포함하므로, lib를 직접 설정하지 않으면 Node.js 프로젝트에서도 document가 타입 검사를 통과합니다. lib보다 새로운 표준의 메서드를 쓰면 컴파일 오류입니다.
src/b.ts(1,24): error TS2550: Property 'toSorted' does not exist on type 'number[]'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2023' or later.
이 문서의 실행 가능한 예제는 es2022 lib를 쓰므로, 예제에서는 toSorted, Object.groupBy, 새 Set 메서드를 쓸 수 없습니다.
module과 moduleResolution
새 코드에서 module에 쓸 만한 값은 세 가지입니다.
nodenext: Node.js가 실행하는 코드용입니다. 각 파일은 확장자(.mts,.cts)나 가장 가까운package.json의"type"에 따라, Node가 판단하는 방식 그대로 ESM이나 CommonJS가 됩니다. ES 모듈의 상대 경로 import에는 파일 확장자가 필요한데, 소스가.ts여도.js로 씁니다:import { add } from "./math.js".moduleResolution은 자동으로 따라갑니다.preserve: 번들러가 처리하는 코드용입니다. import는 쓴 그대로 남고, 해석에는 확장자 없는 import를 허용하는bundler규칙을 씁니다.esnext:bundler해석을 쓰는 일반 ES 모듈 출력입니다.module을 설정하지 않았을 때의 기본값입니다.
tsc --init 설정에서 처음 흔히 만나는 오류는 npm init -y가 "type": "commonjs"를 쓰는 데서 옵니다.
src/main.ts(1,10): error TS1295: ECMAScript imports and exports cannot be written in a CommonJS file under 'verbatimModuleSyntax'.
파일은 import를 쓰는데 package.json은 프로젝트가 CommonJS라고 말합니다. "type"을 "module"로 바꾸세요. import와 export는 모듈 페이지에서 자세히 다룹니다.
strict와 검사 옵션
"strict": true는 여러 검사를 한꺼번에 켭니다: noImplicitAny, strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, strictBuiltinIteratorReturn, noImplicitThis, useUnknownInCatchVariables. TypeScript 7의 기본값이며, 여기의 모든 실행 가능한 예제에서 켜져 있습니다. strict 모드용으로 작성한 코드는 없을 수도 있는 값을 쓰기 전에 좁힙니다.
표기가 없으면 매개변수의 타입을 추론할 수 없고, noImplicitAny가 이를 보고합니다.
index.ts(2,17): error TS7006: Parameter 'n' implicitly has an 'any' type.
strict에 유용한 검사가 모두 들어 있지는 않습니다. 더할 만한 것 두 가지는 noUncheckedIndexedAccess(배열 요소나 인덱스 시그니처 조회의 타입이 T | undefined가 됨)와 exactOptionalPropertyTypes(선택적 속성에 undefined를 명시적으로 넣을 수 없음)이며, tsc --init은 둘 다 켭니다. noUnusedLocals, noImplicitReturns, noFallthroughCasesInSwitch 같은 스타일 검사는 기본으로 꺼져 있습니다.
어떤 파일을: include, exclude, rootDir, outDir
include나 files가 없으면 프로젝트에는 폴더와 하위 폴더의 모든 .ts, .tsx, .d.ts 파일이 들어갑니다. node_modules는 항상 빠집니다. outDir도 빠지지만 exclude를 설정하지 않았을 때만입니다. 직접 쓴 exclude 목록은 이 기본값을 대체하므로 출력 폴더를 목록에 추가하세요. include와 exclude는 glob 패턴을 받습니다.
{
"include": ["src", "scripts/**/*.ts"],
"exclude": ["src/**/*.test.ts"]
}
exclude는 include가 찾은 것을 걸러 낼 뿐입니다. 포함된 다른 파일이 import하는 파일은 여전히 컴파일됩니다.
outDir은 출력이 가는 곳이고, rootDir은 소스 트리 중 그 안에 그대로 옮겨지는 부분입니다. "rootDir": "./src"이면 src/api/users.ts는 dist/api/users.js가 됩니다. 둘 다 설정하세요. rootDir의 기본값은 tsconfig.json이 있는 폴더이므로, 소스가 src에 있는데 outDir만 설정하면 TypeScript 7은 이렇게 멈춥니다.
error TS5011: The common source directory of 'tsconfig.json' is './src'. The 'rootDir' setting must be explicitly set to this or another path to adjust your output's file layout.
출력 옵션: noEmit, declaration, sourceMap
"noEmit": true는tsc를 순수한 타입 검사기로 만듭니다. 다른 도구(번들러,tsx, Node.js 타입 제거)가 JavaScript를 만들 때 쓰세요."declaration": true는 모듈마다 코드 없이 타입만 담은.d.ts파일을 씁니다. 라이브러리는 사용자가 타입을 얻을 수 있도록 이것이 필요합니다.declarationMap은.ts소스로 "정의로 이동"할 수 있는 맵을 더합니다."sourceMap": true는.js.map파일을 써서 디버거와 스택 트레이스가.ts의 줄을 가리키게 합니다."noEmitOnError": true는 타입 오류가 있는 동안 아무것도 쓰지 않습니다. 이 옵션이 없으면tsc는 오류를 보고하고도 JavaScript를 씁니다.
types, esModuleInterop, skipLibCheck
types는 import 없이 전역으로 불러올 @types 패키지를 나열합니다. TypeScript 7의 기본값은 빈 목록이므로, npm install --save-dev @types/node 뒤에 "types": ["node"]도 추가해야 합니다. 그러지 않으면 process와 require를 알 수 없는 상태로 남습니다(error TS2591: Cannot find name 'process'). Jest의 describe처럼 전역 함수가 있는 테스트 러너도 같은 목록에 넣습니다.
esModuleInterop은 CommonJS 패키지의 기본 import(import express from "express")가 동작하게 합니다. TypeScript 7에서는 항상 켜져 있고, false로 설정하면 오류입니다.
skipLibCheck는 선언 파일의 타입 검사를 건너뜁니다. 빌드가 빨라지고 고칠 수 없는 node_modules 내부의 오류를 피할 수 있지만, 두 라이브러리 타입 사이의 충돌을 알아채지 못한다는 대가가 있습니다. 대부분의 프로젝트가 켭니다.
extends로 설정 공유하기
extends는 다른 설정을 불러오고, 이 파일에서 그 일부를 덮어쓰게 합니다.
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": ["src"]
}
compilerOptions는 옵션 단위로 병합되지만, 이 파일이 include, exclude, files를 설정하면 기반 파일의 값은 병합되지 않고 대체됩니다. 기반 파일의 경로는 기반 파일을 기준으로 해석됩니다. extends는 패키지도 받습니다. @tsconfig/bases 프로젝트는 환경별로 하나씩 배포합니다. 예를 들어 npm install --save-dev @tsconfig/node24 후 "extends": "@tsconfig/node24/tsconfig.json"이라고 씁니다.
모든 extends와 기본값이 적용된 최종 설정을 보려면 이렇게 실행하세요.
npx tsc --showConfig
TypeScript 7에서 제거된 옵션
TypeScript 6이 폐기한 다음 설정들은 TypeScript 7에서 제거되었습니다. 아직 이 중 하나를 쓰는 설정은 error TS5108이나 TS5102로 실패합니다. 예: Option 'baseUrl' has been removed. Please remove it from your configuration.
| 제거된 설정 | 대신 쓸 것 |
|---|---|
"target": "es5" | es2015 이상 |
"moduleResolution": "node" (node10) 또는 "classic" | nodenext 또는 bundler |
"module": "amd", "umd", "system", "none" | nodenext, esnext, preserve, 그리고 다른 형식에는 번들러 |
baseUrl | tsconfig 파일 기준의 paths 항목 |
outFile | 번들러 |
downlevelIteration | 필요 없음: es2015 이상의 target은 순회를 기본 지원 |
"esModuleInterop": false, "allowSyntheticDefaultImports": false, "alwaysStrict": false | 그 줄을 지우세요. 항상 켜져 있습니다 |
이 릴리스의 다른 변경 사항은 이 표가 다루지 않는 새 기본값을 포함해 TypeScript 7 페이지에 정리되어 있습니다.
자주 묻는 질문
tsconfig.json이란 무엇인가요?
TypeScript 프로젝트의 설정 파일입니다. 이 파일이 있으면 그 폴더가 프로젝트 루트가 되고, compilerOptions는 컴파일러가 코드를 검사하고 출력하는 방식을 정하며, include, exclude, files는 어떤 파일이 프로젝트에 속하는지 정합니다. 인수 없이 tsc를 실행하면 이 파일을 읽습니다.
tsconfig.json 파일은 어떻게 만드나요?
TypeScript가 설치된 프로젝트 폴더에서 npx tsc --init을 실행하세요. 권장 설정과 각 옵션의 주석이 담긴 tsconfig.json을 씁니다. 파일을 직접 작성해도 됩니다. {}도 모든 기본값을 쓰는 올바른 tsconfig입니다.
tsconfig의 target은 무엇으로 설정해야 하나요?
코드가 실행되어야 하는 가장 오래된 JavaScript 버전입니다. 최신 Node.js라면 es2022 이상이 안전하며, TypeScript 7의 기본값은 es2025입니다. target은 오래된 엔진을 위해 어떤 최신 문법을 다시 쓸지 정하고, 검사기가 아는 내장 API 집합인 기본 lib도 정합니다.
module과 moduleResolution의 차이는 무엇인가요?
module은 컴파일러가 쓰는 모듈 코드의 종류(ES import/export 또는 CommonJS require)와 적용할 모듈 규칙을 정합니다. moduleResolution은 "./utils.js"나 "lodash" 같은 import 경로를 디스크에서 어떻게 찾을지 정합니다. Node.js가 실행하는 코드에는 nodenext를, 번들러가 처리하는 코드에는 module: "preserve"(bundler 해석을 함께 뜻함)를 쓰세요.
tsconfig.json에 주석을 쓸 수 있나요?
네. 컴파일러는 이 파일을 주석이 허용된 JSON으로 읽습니다. //와 /* */ 주석, 끝의 쉼표가 허용되며, 그래서 tsc --init이 주석 처리된 옵션으로 가득한 파일을 씁니다. 이 파일을 엄격한 JSON으로 파싱하는 다른 도구는 실패할 수 있습니다.