TechFeedTechFeed
Programming Languages

타입 스트리핑, enum, tsx | 노드가 ts를 돌리면 어디서 멈추나?

노드가 ts 파일을 직접 돌리면 타입은 공백으로 지우고 검사는 하지 않는다. 타입 스트리핑, 이레이저블 신택스, enum, 생성자 공개 인자, tsx, tsc 무출력, 노드 24 LTS, 타입스크립트 5.8, 개발자, API, Next.js 스크립트를 같은 표에 둔다. 넥스트 앱 변환과 파이썬 타입체크 글과 자리를 섞지 않는다.

by

지난주 배포 스크립트를 tsx 없이 돌리려다 enum에서 멈췄습니다. 노드 22.18부터는 플래그 없이 ts 파일을 실행합니다. 타입은 공백으로 지우고, 검사는 하지 않습니다. 24.12에서 타입 스트리핑이 안정으로 올랐고, 26은 변환 플래그를 뺐습니다. enum과 생성자 공개 인자는 자바스크립트를 새로 만들어야 해서 거부합니다. 타입스크립트 5.8의 이레이저블 신택스 옵션을 켜면 그 문법을 커밋 전에 잡습니다. 저는 크론 스크립트를 노드로 직접 돌리기 전에 이 옵션과 무출력 검사를 CI에 붙였습니다.


넥스트 앱 변환은 프로덕션 체크리스트에 두고, 여기는 노드가 ts를 직접 도는 자리만 봅니다. 숫자는 2026년 8월 노드 타입스크립트 문서와 타입스크립트 5.8 릴리스 노트 기준입니다.


노드가 타입을 공백으로 바꾸는 자리

실행은 합니다. 타입 검사는 안 합니다. 주석만 공백으로 지우고 남은 자바스크립트를 돌립니다.


노드 문서는 이렇게 적습니다. 지울 수 있는 타입스크립트 문법만 기본으로 실행한다. 인라인 타입을 공백으로 바꿔서 줄 번호가 유지됩니다. 소스맵을 만들지 않습니다. tsconfig.json은 읽지 않습니다. 경로 별칭, 옛 문법으로의 다운레벨, 설정에 묶인 변환은 의도적으로 빠집니다. 전체 문법이 필요하면 문서가 예로 든 tsx 같은 서드파티를 씁니다.


버전바뀐 점지금 쓸 때
22.6실험 플래그로 타입 스트리핑 추가22.18 미만이면 플래그가 필요
22.18, 23.6기본으로 켜짐. 실험 경고는 24.3, 22.18에서 사라짐node file.ts만으로 실행
24.12, 25.2타입 스트리핑 안정24 LTS를 쓰는 1인 팀의 출발점
26.0변환 플래그 제거이넘을 런타임에서 바꿔 주지 않음

끄는 플래그는 --no-strip-types입니다. 끄면 .ts는 그냥 실행되지 않습니다. 정본은 노드 타입스크립트 모듈 문서입니다. 파이썬 쪽 검사 칸은 파이라이트 체크에 있고, 여기는 런타임이 타입을 지우는 자리만 봅니다.


버전 확인 뒤 ts를 직접 실행하고, 검사는 따로
node --version node ./scripts/publish.ts npx tsc --noEmit

실행과 검사는 한 명령이 아니다 | node file.ts가 통과해도 타입은 틀린 수 있습니다. 노드 배우기 페이지도 검사를 tsc --noEmit으로 분리하라고 적습니다. 로컬에서 바로 도는 것과 CI에서 막는 것을 같은 칸에 두지 않습니다.


enum과 생성자 인자가 멈추는 네 자리

공백으로 지울 수 없으면 에러입니다. 이넘, 값이 있는 네임스페이스, 생성자 공개 인자, import 별칭이 그 네 칸입니다.


노드는 타입스크립트 문법을 자바스크립트로 다시 쓰지 않습니다. 지울 수 있는 주석만 뺍니다. 그래서 enum Direction { Up, Down }ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX로 멈춥니다. 값이 있는 namespace도 같습니다. 타입만 내보내는 네임스페이스는 됩니다. 클래스 생성자에 public x: number를 붙이는 자리, import foo = require("foo")export =도 런타임 코드가 생겨서 거부됩니다.


문법노드 직접 실행바꿀 때
타입 주석, 인터페이스, 타입만 있는 import됨. 공백으로 지움그대로 둠
enum거부as const 객체와 유니온
값이 있는 네임스페이스거부모듈로 나눔. 타입만 있는 칸은 유지
생성자 공개 인자거부본문에서 this.x = x
import =, export =거부표준 import, export
데코레이터, .tsx미지원tsx나 넥스트 변환

타입스크립트 5.8의 erasableSyntaxOnly가 같은 네 칸을 컴파일 단계에서 막습니다. 노드가 나중에 던질 에러를 에디터에서 먼저 봅니다. 블룸버그 ts-blank-space와 노드 아마로가 같은 한계를 가집니다. 릴리스 노트는 타입스크립트 5.8 문서입니다.


이넘을 상수 객체로 바꿔 노드가 받게 하는 예
// 거부. 런타임 객체를 만들어야 함 enum Direction { Up, Down, } // 허용. 지울 타입이 주석뿐 const Direction = { Up: 'Up', Down: 'Down', } as const type Direction = (typeof Direction)[keyof typeof Direction] class Point { x: number y: number constructor(x: number, y: number) { this.x = x this.y = y } }
노드 타입 스트리핑이 거부하는 네 문법과 바꿀 자리
이넘과 생성자 공개 인자는 공백으로 지울 수 없다. 상수 객체와 본문 대입으로 바꾼다

tsconfig는 노드가 읽지 않는다

설정 파일은 에디터와 tsc용입니다. 런타임은 확장자와 package.json의 type만 봅니다.


문서가 권하는 설정은 타입스크립트 5.8 이상, target은 esnext, module은 nodenext입니다. erasableSyntaxOnly로 지울 수 없는 문법을 막고, verbatimModuleSyntax로 타입 import에 type 키워드를 강제합니다. rewriteRelativeImportExtensions는 상대 경로의 .ts를 빌드 결과에서 .js로 바꿉니다. 스크립트만 직접 실행하면 noEmit을 켭니다. 배포물에 js를 남기면 이 옵션은 끕니다.


모듈 칸은 파일 확장자가 정합니다. .mts는 ESM, .cts는 CommonJS입니다. .ts는 가까운 package.json"type": "module"을 따릅니다. import './file'처럼 확장자를 빼면 거절됩니다. import './file.ts'가 맞습니다. tsc가 그 경로를 받으려면 allowImportingTsExtensions가 필요합니다. paths 별칭은 변환되지 않습니다. 가까운 대체는 #로 시작하는 서브패스 imports입니다.


type 없이 타입만 가져오면 런타임 에러입니다. 노드는 그 줄을 값 import로 남깁니다. import type { Row }이거나 import { fn, type Row }처럼 칸을 나눕니다. 정본 설정은 같은 타입 스트리핑 절에 있습니다.


노드 직접 실행에 맞춘 tsconfig 최소 칸
{ "compilerOptions": { "noEmit": true, "target": "esnext", "module": "nodenext", "rewriteRelativeImportExtensions": true, "erasableSyntaxOnly": true, "verbatimModuleSyntax": true, "allowImportingTsExtensions": true } }

타입 검사는 CI에 따로 둔다

로컬은 node script.ts로 빠르게 보고, 머지 전에 tsc --noEmit을 한 번 돌립니다. 두 명령을 한 줄로 합치지 않습니다.


12사이트 크론은 예전에 tsx로 한 줄을 감쌌습니다. 의존이 늘고, 깃허브 액션 이미지가 커졌습니다. 노드 24로 올린 뒤 배포 스크립트는 node ./scripts/foo.ts로 바꿨습니다. 그날 바로 깨진 파일은 상태 이넘이 있는 한 개였습니다. 상수 객체로 고치고, 저장소 루트 tsconfig에 이레이저블 옵션을 켰습니다. 그다음부터는 푸시 전에 에디터가 같은 자리를 밑줄로 그었습니다.


테스트 러너는 이 글의 주제가 아닙니다. 비테스트와 제스트 비교는 비테스트 비교에 있습니다. 파이썬 패키지 칸은 uv 글에 있습니다. 여기는 런타임이 타입을 안 본다는 한 줄만 남깁니다. 한국 1인 팀은 액션 분을 아끼려고 검사 단계를 빼기 쉽습니다. 빼면 enum을 고친 줄이 메인에 들어가고, 크론이 새벽에 죽습니다.


노드 실행과 tsc 검사, tsx 변환을 나눈 역할 표
실행은 노드, 검사는 tsc, 변환이 남은 자리만 tsx다. 한 도구에 세 칸을 맡기지 않는다

넥스트 앱과 노드 스크립트는 같은 설정이 아니다

넥스트는 자체 변환으로 .tsx를 돌립니다. 노드 내장 스트리핑은 그 파일을 받지 않습니다.


앱 라우트의 페이지와 서버 액션은 넥스트가 타입스크립트를 처리합니다. 그 칸에 노드 직접 실행 설정을 복사하면 확장자 규칙과 경로 별칭이 엇갈립니다. 반대로 scripts/ 아래 발행, 사이트맵, 썸네일 생성은 넥스트 밖입니다. 그 칸이 이 글의 대상입니다. 저는 루트 tsconfig를 앱용으로 두고, 스크립트 폴더만 이레이저블 옵션을 켠 작은 설정을 물립니다. 한 파일에 두 환경을 섞으면 paths가 스크립트에서 터집니다.


의존성 안의 ts는 노드가 거부합니다. node_modules 아래 타입스크립트를 직접 실행하지 말라는 뜻입니다. 패키지를 배포할 때는 js를 남깁니다. 배우기 페이지의 패키지 발행 절과 같습니다. 자바 가상 스레드처럼 런타임 기본값이 바뀌는 자리는 히카리 글과 성격이 비슷합니다. 기본이 켜졌다고 예전 문법을 그대로 두면, 새 런타임에서 먼저 죽습니다.


타입 import는 type 키워드를 붙인다
import type { PostMeta } from './types.ts' import { loadPost, type LoadOpts } from './load.ts' export async function run(opts: LoadOpts) { const row = await loadPost(opts) return row.id }

tsx를 남길 자리와 빼는 자리

리액트 tsx, 데코레이터, 이넘을 당장 못 지우는 레거시만 tsx를 둡니다. 크론과 순수 스크립트는 노드 직접 실행으로 옮깁니다.


노드 문서도 전체 문법 지원의 예로 tsx를 적습니다. npx tsx file.ts 또는 node --import=tsx file.ts입니다. 26에서 변환 플래그가 빠졌기 때문에, 이넘을 런타임이 대신 바꿔 주길 바라면 서드파티가 맞습니다. 다만 의존을 하나 더 두는 대가입니다. 저는 발행 스크립트 여섯 개를 상수 객체로 고치는 데 반나절이 걸렸습니다. 그다음 액션에서 tsx를 뺐고, 설치 시간이 눈에 띄게 줄었습니다.


자리실행이유
크론, 발행, 사이트맵 스크립트node file.ts지울 문법만 있으면 의존이 필요 없음
넥스트 페이지, 서버 액션넥스트 빌드.tsx와 앱 변환
리액트 컴포넌트를 노드에서 렌더tsx내장은 .tsx 미지원
이넘을 당장 못 지우는 레거시tsx, 기한 후 이전26은 변환 플래그가 없음

한국 호스팅 이미지에 노드 22.17이 남아 있으면 플래그가 필요합니다. 가비아, 카페24 애플리케이션 노드, 깃허브 액션 actions/setup-node의 기본값을 먼저 봅니다. 22.18 이상이면 플래그 없이 됩니다. 배우기 페이지는 네이티브 실행 가이드입니다. tsx 설치 예는 노드가 가리키는 tsx 문서입니다.


크론은 노드 직접 실행, 넥스트는 자체 변환, 리액트 tsx만 tsx를 남기는 순서
스크립트는 노드, 앱은 넥스트, 컴포넌트 렌더만 tsx다. 세 칸을 한 명령으로 묶지 않는다

참고 자료


버전과 플래그는 릴리스마다 바뀝니다. 위 표는 2026년 8월 공개 페이지 기준 점검용이며, 최종 근거는 각 문서와 로컬 node --version입니다.


자주 묻는 질문

노드가 ts를 돌리면 타입 검사도 하나?

하지 않습니다. 타입 주석을 공백으로 지운 뒤 남은 코드를 실행합니다. 틀린 타입도 런타임까지 갑니다. 머지 전에 tsc --noEmit을 한 줄 둡니다. 로컬에서 바로 도는 속도와 검사 칸을 나누는 편이 낫습니다.


enum을 꼭 상수 객체로 바꿔야 하나?

노드 직접 실행을 쓰려면 바꿉니다. 이넘은 자바스크립트 객체를 새로 만들어야 해서 거부됩니다. tsx를 남기면 당장은 됩니다. 노드 26은 변환 플래그를 뺐습니다. 크론 스크립트는 반나절 들여 상수 객체로 옮기는 편이 이후 의존이 줄어듭니다.


tsx를 지금 저장소에서 지워도 되나?

순수 스크립트만 있으면 지울 수 있습니다. 리액트 tsx 파일을 노드에서 렌더하거나 데코레이터가 남으면 유지합니다. 지운 뒤 CI에서 node script.tstsc --noEmit이 둘 다 통과하는지 봅니다. 하나라도 실패하면 그 파일만 되돌립니다.


넥스트 앱에도 이레이저블 옵션을 켜나?

앱 칸과 스크립트 칸을 나눕니다. 넥스트는 자체 변환으로 tsx를 돌립니다. 루트 설정에 이 옵션을 켜면 페이지 컴포넌트의 생성자 문법까지 밑줄이 갑니다. 스크립트 폴더만 작은 tsconfig로 물리는 편이 안전합니다.


노드 22와 24, 26 중 어디에 맞추나?

한국 1인 팀은 24 LTS가 출발점입니다. 22.18 이상이면 플래그 없이 됩니다. 22.17 이하면 실험 플래그가 필요합니다. 26은 변환 플래그가 없어서 이넘을 런타임이 대신 바꿔 주지 않습니다. 호스팅 이미지와 액션 노드 버전을 먼저 찍어둡니다.


패키지 안의 ts 파일을 노드가 실행하나?

하지 않습니다. node_modules 아래 타입스크립트는 거부합니다. 라이브러리를 배포할 때는 js를 남깁니다. 앱 코드의 ts만 직접 실행하는 전제입니다. 타입 선언 파일은 검사 도구가 읽고, 런타임은 읽지 않습니다.


타입 스트리핑이레이저블 신택스enumtsx타입스크립트노드개발자APINext.jsCItsc

함께 보면 좋은 문제 해결

EXPLORE / Programming Languages

이어서 읽어보기

전체 토픽 둘러보기