빠른 설정
{
"compilerOptions": {
"isolatedModules": true,
"verbatimModuleSyntax": true
}
}| 환경 | 확인할 점 |
|---|---|
tsc만 사용 | 전체 타입 정보를 보고 emit 가능 |
| Babel, SWC, esbuild 사용 | 파일 하나씩 변환하므로 제한 필요 |
| Vite, Next.js, ts-loader transpileOnly | type check와 transpile 경계 분리 |
변환 경계
isolatedModules는 단일 파일 변환에서 위험한 코드를 미리 막는다
TypeScript 컴파일러는 프로젝트 전체 타입 정보를 보고 JavaScript를 만들 수 있습니다. 하지만 Babel, SWC, esbuild 같은 변환기는 보통 파일 하나만 보고 TypeScript 문법을 지웁니다. 이때 타입인지 값인지, namespace가 런타임에 필요한지 같은 정보를 전체 프로젝트 기준으로 판단할 수 없습니다.
import { User, createUser } from "./user";
export { User, createUser };User가 type-only export라면 런타임 JavaScript에는 존재하지 않습니다. 단일 파일 변환기는 User가 값인지 타입인지 확신하기 어렵기 때문에, isolatedModules는 이런 코드를 더 명시적으로 쓰게 만듭니다.
import type { User } from "./user";
import { createUser } from "./user";
export type { User };
export { createUser };이 옵션은 타입 검사를 더 엄격하게 하는 옵션이 아니다
isolatedModules는 타입 안정성을 직접 높이는 옵션이라기보다 emit 가능성을 검증하는 옵션입니다. 켠다고 JavaScript 출력이 달라지는 것은 아니며, 단일 파일 변환 도구가 안전하게 처리하기 어려운 패턴을 오류로 알려 줍니다.
{
"compilerOptions": {
"noEmit": true,
"isolatedModules": true
}
}빌드는 SWC가 하고 타입 검사는 tsc --noEmit이 하는 프로젝트에서는 위 조합이 흔합니다. 실제 출력은 SWC가 만들지만, TypeScript가 단일 파일 변환에 위험한 문법을 사전에 잡습니다.
namespace와 const enum은 특히 주의한다
namespace는 파일이 모듈인지 전역 script인지에 따라 emit 의미가 달라질 수 있습니다. isolatedModules가 켜진 상태에서는 전역 script 파일의 namespace 같은 패턴이 제한됩니다. 파일이 모듈이어야 한다면 import나 export {}로 모듈 경계를 분명히 합니다.
export {};
namespace Internal {
export const value = 1;
}ambient const enum도 단일 파일 변환에서 문제가 됩니다. TypeScript는 const enum 값을 inline할 수 있지만, 다른 변환기는 타입 선언만 보고 실제 값을 알 수 없습니다. 라이브러리 경계에서는 const enum보다 union literal이나 일반 객체를 쓰는 편이 더 이식성이 좋습니다.
verbatimModuleSyntax와 함께 쓰면 type-only 경계가 더 명확해진다
verbatimModuleSyntax는 import/export를 작성한 대로 보존하고 type-only 문법만 제거하는 방향의 옵션입니다. isolatedModules와 함께 쓰면 "값 import인지 타입 import인지"를 파일 안에서 더 명확히 드러내게 됩니다.
import type { Config } from "./types";
import { loadConfig } from "./runtime";
export type { Config };
export { loadConfig };이 방식은 빌드 도구, 린터, bundler가 같은 import 의미를 공유하게 만드는 데 도움이 됩니다. 특히 ESM 프로젝트에서 type-only import를 명시하지 않으면 런타임 import가 남거나, 반대로 필요한 값 import가 사라지는 문제를 추적하기 어려워집니다.
적용 기준
| 상황 | 권장 |
|---|---|
tsc가 직접 emit | 선택 사항 |
| Babel/SWC/esbuild가 TS 제거 | isolatedModules 권장 |
| 타입 검사와 번들링이 분리됨 | tsc --noEmit + isolatedModules |
| type-only import/export가 많음 | import type, export type 정리 |
const enum, namespace를 많이 사용 | 대체 모델 검토 |
현대 프론트엔드 프로젝트에서는 TypeScript가 타입 검사만 하고 실제 변환은 bundler가 담당하는 경우가 많습니다. 이 구조에서는 isolatedModules를 켜서 "파일 하나만 봐도 안전한 TypeScript"인지 확인하는 편이 운영상 유리합니다.
주의할 점
isolatedModules는 전체 타입 검사를 대체하지 않습니다.
단일 파일 변환 가능성만 확인하므로, 여전히 tsc --noEmit이나 동등한 타입 검사 단계가 필요합니다.
{
"scripts": {
"typecheck": "tsc --noEmit",
"build": "vite build"
}
}오류를 줄이려고 isolatedModules를 끄면 빌드 도구가 처리하지 못하는 코드가 런타임까지 넘어갈 수 있습니다. 옵션을 끄기보다 type-only export, namespace, const enum 사용을 먼저 정리하는 편이 안전합니다.
참고 링크
2 sources