본문으로 건너뛰기

TypeScript 7 네이티브 컴파일러 전환 가이드: Go 포트 성능·호환성·CI 마이그레이션

TypeScript16분 읽기본문 8,120

핵심 요약

이 글에서 확인할 내용

컴파일러가 바뀌면 업그레이드 방법도 달라진다 TypeScript 7.0이 2026년 7월 정식 출시되었습니다. 이번 버전은 몇 가지 타입 문법을 추가한 일반적인 메이저 업데이트가 아닙니다. 10년 넘게 JavaScript로 구현되어 온 컴파일러와 언어 서비스를 Go 기반 네이티브 코드로 다시 만든 전환점입니다.

  • 1. TypeScript 7에서 실제로 바뀐 경계
  • 2. 먼저 TypeScript 6을 통과해야 하는 이유
  • 3. 의존성 지도를 먼저 만든다

TypeScript 6과 TypeScript 7을 병행 검증하며 네이티브 컴파일러로 전환하는 흐름

컴파일러가 바뀌면 업그레이드 방법도 달라진다

TypeScript 7.0이 2026년 7월 정식 출시되었습니다. 이번 버전은 몇 가지 타입 문법을 추가한 일반적인 메이저 업데이트가 아닙니다. 10년 넘게 JavaScript로 구현되어 온 컴파일러와 언어 서비스를 Go 기반 네이티브 코드로 다시 만든 전환점입니다. TypeScript 팀이 공개한 대규모 오픈소스 프로젝트 측정에서는 전체 빌드가 대체로 8~12배 빨라졌고, 파싱·타입 검사·출력 단계가 멀티코어를 활용하도록 재설계되었습니다(TypeScript 7.0 공식 발표).

그러나 typescript 패키지 버전만 7로 올리는 것은 안전한 마이그레이션 전략이 아닙니다. TypeScript 7.0에는 안정적인 컴파일러 API가 없고, TypeScript 6.0에서 예고된 설정 변경과 지원 종료 항목이 7.0에서는 오류로 바뀝니다. Vue·Svelte·Astro·MDX·Angular처럼 TypeScript API나 언어 서비스 플러그인에 의존하는 도구도 아직 6.0 경로가 필요할 수 있습니다.

이 글에서는 성능 수치보다 어떻게 위험을 격리하면서 전환할지에 집중합니다. 먼저 TypeScript 6.0으로 설정 부채를 정리하고, 6과 7의 진단 결과를 CI에서 비교한 다음, 도구 체인별로 실행 파일을 분리하는 순서를 다룹니다. 명령은 npm 기준이지만 pnpm과 Yarn에서도 같은 원칙을 적용할 수 있습니다.

1. TypeScript 7에서 실제로 바뀐 경계

TypeScript 7의 핵심은 네이티브 실행 파일과 LSP(Language Server Protocol) 기반 언어 서비스입니다. 기존 컴파일러의 구조와 의미를 최대한 보존하면서 Go로 포팅했고, 공유 메모리 멀티스레딩을 사용합니다. 기본 타입 검사 워커 수는 4개이며 --checkers로 조절할 수 있습니다. 프로젝트 레퍼런스 빌드는 --builders로 동시에 처리할 프로젝트 수를 정할 수 있고, 재현이나 디버깅이 필요하면 --singleThreaded로 병렬화를 끌 수 있습니다.

공식 발표의 동일 장비 측정치는 다음과 같습니다. 이 숫자는 제품 보증치가 아니라 해당 저장소와 장비에서 얻은 결과이므로, 자사 코드베이스의 기대값으로 그대로 사용해서는 안 됩니다.

코드베이스TypeScript 6TypeScript 7공식 측정 속도 향상
VS Code125.7초10.6초11.9배
Sentry139.8초15.7초8.9배
Playwright12.8초1.47초8.7배
tldraw11.2초1.46초7.7배

성능만 보고 즉시 교체하기 어려운 이유는 API 경계입니다. tsc 명령과 에디터용 LSP는 사용할 수 있지만, 7.0은 createProgram, TypeChecker, AST transformer 같은 프로그래밍 API를 제공하지 않습니다. 빌드 플러그인, 린터, 코드 생성기, 프레임워크 언어 서버가 import ts from 'typescript' 형태로 API를 호출한다면 TypeScript 6 호환 패키지를 함께 유지해야 합니다. 새 API는 7.1에서 제공될 예정이라고 공식 발표에 명시되어 있습니다.

즉 전환 대상을 하나로 보면 안 됩니다.

  • CLI 타입 검사: 네이티브 tsc로 가장 먼저 옮길 수 있습니다.
  • 에디터 언어 서비스: LSP 지원 여부와 프레임워크 플러그인 의존성을 따로 확인합니다.
  • 컴파일러 API 소비 도구: 7.0에서 바로 옮기지 말고 TypeScript 6 호환 계층을 유지합니다.
  • 번들러 변환: SWC·esbuild·Babel이 코드를 변환하고 tsc --noEmit은 타입만 검사하는 구조라면 비교적 분리가 쉽습니다.

2. 먼저 TypeScript 6을 통과해야 하는 이유

TypeScript 7은 TypeScript 6의 타입 검사와 명령행 동작을 호환 기준선으로 삼습니다. 공식 안내에 따르면 TypeScript 6에서 stableTypeOrdering을 켜고 ignoreDeprecations를 사용하지 않은 상태로 깨끗하게 컴파일되는 코드는 대부분 7에서도 동일하게 컴파일됩니다. 따라서 5.x에서 7로 한 번에 건너뛰기보다 6을 징검다리로 사용하는 편이 오류 원인을 분리하기 쉽습니다.

TypeScript 6에서 바뀐 기본값 중 특히 점검할 항목은 다음과 같습니다(TypeScript 6.0 공식 발표).

설정TypeScript 7 기본 동작마이그레이션 시 확인할 문제
stricttrue암시적 any, nullable 값, 함수 분산 오류 증가
moduleesnextCommonJS 전용 실행 환경과 출력 형식 충돌
target직전 안정 ECMAScript 버전구형 브라우저·런타임 지원 범위 변경
noUncheckedSideEffectImportstrue존재하지 않는 CSS·에셋 side-effect import 탐지
rootDir./기존 src 기준 출력 디렉터리 구조 변화
types[]Node, Jest, Vitest 등의 전역 타입이 사라짐

기본값에 맡겨 우연히 동작하던 프로젝트라면 업그레이드 전에 의도를 명시하는 것이 좋습니다. 예를 들어 Node 기반 테스트와 브라우저 애플리케이션을 하나의 설정에 섞지 말고, 공통 설정을 확장한 별도 설정으로 나눕니다.

// tsconfig.json — 애플리케이션 기준선
{
  "compilerOptions": {
    "target": "ES2023",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "strict": true,
    "noEmit": true,
    "rootDir": "./src",
    "types": []
  },
  "include": ["src"]
}
// tsconfig.test.json — 테스트 런타임의 전역 타입만 추가
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "types": ["node", "vitest/globals"]
  },
  "include": ["src", "tests", "vitest.config.ts"]
}

target: es5, moduleResolution: node 또는 classic, module: amd|umd|systemjs, baseUrl, downlevelIteration 같은 항목은 7에서 더 이상 지원되지 않습니다. esModuleInterop: falseallowSyntheticDefaultImports: false도 사용할 수 없습니다. ignoreDeprecations: "6.0"으로 경고를 잠시 숨길 수는 있지만 7에서는 탈출구가 되지 않으므로, CI 전환 전에 제거해야 합니다.

3. 의존성 지도를 먼저 만든다

package.json만 보아서는 어떤 도구가 TypeScript API를 호출하는지 전부 알기 어렵습니다. 직접 의존성과 peer dependency를 함께 조사해야 합니다.

# 설치된 TypeScript와 의존 경로 확인
npm ls typescript --all

# 저장소에서 컴파일러 API를 직접 가져오는 코드 탐색
rg "from ['"]typescript['"]|require\(['"]typescript['"]\)" \
  --glob '!node_modules/**'

# 기존 설정의 실제 해석 결과 보관
npx tsc --showConfig > .artifacts/ts6-config.json

마지막 명령의 결과 파일을 커밋할 필요는 없습니다. CI 아티팩트로 보관해 버전별 설정 차이를 비교하면 됩니다. 점검 결과는 다음 세 그룹으로 분류합니다.

  1. 순수 CLI 사용자: tsc --noEmit이나 tsc -b만 호출합니다. TypeScript 7 전환 우선순위가 가장 높습니다.
  2. API 소비자: typescript-eslint, 커스텀 transformer, AST 기반 코드 생성기, 일부 문서화 도구가 해당합니다. 6.0 호환 패키지와 도구별 지원 공지를 확인합니다.
  3. 임베디드 언어 사용자: Vue SFC, Svelte, Astro, MDX, Angular 템플릿처럼 TypeScript가 다른 언어 안에 들어갑니다. 공식 7.0 발표는 이 워크플로가 아직 네이티브 언어 서비스를 활용하지 못할 수 있다고 명시합니다.

이 분류를 하지 않으면 CLI는 빨라졌는데 ESLint가 실행되지 않거나, 터미널에서는 오류가 없는데 에디터가 다른 진단을 표시하는 상태가 생깁니다. 모노레포라면 패키지 단위가 아니라 실행 경로 단위로 분류하는 것이 핵심입니다. 같은 패키지도 빌드에서는 CLI만 쓰고 린트에서는 API를 사용할 수 있기 때문입니다.

4. TypeScript 6과 7을 나란히 설치하는 방법

API 의존 도구가 있는 저장소는 TypeScript 팀이 제공하는 @typescript/typescript6 호환 패키지를 사용합니다. 이 패키지는 TypeScript 6 API를 다시 내보내며 실행 파일 이름은 tsc6입니다. typescript라는 패키지 이름을 peer dependency로 요구하는 도구를 위해 npm alias를 사용하고, 네이티브 7은 별도 alias로 둡니다.

{
  "devDependencies": {
    "@typescript/native": "npm:typescript@^7.0.2",
    "typescript": "npm:@typescript/typescript6@^6.0.2"
  },
  "scripts": {
    "typecheck": "tsc --noEmit",
    "typecheck:legacy": "tsc6 --noEmit",
    "typecheck:both": "npm run typecheck:legacy && npm run typecheck"
  }
}

이 배치에서는 typescript import가 필요한 도구는 6.0 API를 보고, tsc6는 기존 컴파일러를 실행합니다. @typescript/native가 제공하는 tsc 바이너리는 7.0을 실행합니다. 설치 후에는 추측하지 말고 바이너리 버전을 CI 로그에 남깁니다.

npx tsc6 --version
npx tsc --version
npx tsc6 --noEmit --pretty false
npx tsc --noEmit --pretty false

API 의존성이 전혀 없고 지원 도구가 모두 7에 맞춰졌다면 단순히 npm install -D typescript로 설치할 수 있습니다. 다만 lockfile 변경 리뷰에서 alias가 사라진 이유와 도구 호환성 확인 결과를 함께 기록해야 다음 의존성 업데이트에서 6 호환 계층이 우연히 복원되는 일을 막을 수 있습니다.

5. 진단 결과를 비교하는 CI 설계

두 컴파일러의 종료 코드만 비교하면 어느 파일의 어떤 오류가 달라졌는지 알 수 없습니다. 전환 기간에는 결과를 파일로 남기고, 새 컴파일러를 처음부터 필수 게이트로 만들지 않는 것이 좋습니다.

# .github/workflows/typecheck.yml 일부
jobs:
  typecheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci

      - name: TypeScript 6 baseline
        run: npx tsc6 --noEmit --pretty false 2>&1 | tee ts6.log

      - name: TypeScript 7 candidate
        continue-on-error: true
        run: npx tsc --noEmit --pretty false 2>&1 | tee ts7.log

      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: typescript-diagnostics
          path: |
            ts6.log
            ts7.log

첫 주에는 6을 필수 게이트, 7을 관찰용으로 둡니다. 오류 수만 세지 말고 진단 코드와 파일 경로를 정규화해 비교합니다. 절대 경로, 실행 시간, ANSI 색상은 제거해야 같은 오류가 불필요한 diff를 만들지 않습니다. 차이가 0이 되고 대상 브랜치에서 일정 기간 안정적으로 유지되면 7을 필수 게이트로 바꾸고, 6은 도구 API 호환성 확인용 작업으로 축소합니다.

프로젝트 레퍼런스를 사용하는 모노레포라면 첫 비교는 병렬 변수 없이 기본값으로 실행합니다. 결과가 안정된 뒤 --builders--checkers를 조절합니다.

# 기준선: 기본 워커 수
/usr/bin/time -l npx tsc -b --pretty false

# CPU와 메모리 여유가 있는 전용 러너 후보
/usr/bin/time -l npx tsc -b --checkers 8 --builders 2 --pretty false

# 재현성 조사 또는 제한된 컨테이너
/usr/bin/time -l npx tsc -b --singleThreaded --pretty false

--checkers 8 --builders 2는 최대 16개의 타입 검사 작업으로 이어질 수 있습니다. 워커를 늘리면 항상 빨라지는 것이 아니며, 메모리가 작은 공유 러너에서는 오히려 스와핑이나 OOM을 유발할 수 있습니다. 실행 시간과 함께 최대 RSS, CPU 사용률, 캐시 유무를 기록해야 의미 있는 비교가 됩니다.

6. 성능 측정은 캐시와 책임 범위를 분리한다

TypeScript 7의 효과를 설명할 때 한 번의 따뜻한(warm) 빌드만 측정하면 결과가 왜곡됩니다. 다음 네 구간을 따로 측정하는 편이 좋습니다.

  • 깨끗한 체크아웃에서 실행한 전체 tsc -b
  • .tsbuildinfo가 있는 증분 빌드
  • 파일 하나를 바꾼 --watch 재검사
  • 에디터를 연 뒤 첫 진단과 참조 찾기까지 걸린 시간

CI에서는 최소 5회 이상 실행한 중앙값과 p95를 비교하고, 러너 종류·코어 수·메모리·Node 버전·lockfile 해시를 결과에 붙입니다. 6과 7을 같은 작업에서 번갈아 실행하면 앞선 실행의 파일 시스템 캐시가 뒤 실행에 유리하게 작용할 수 있으므로 실행 순서를 교차하거나 독립된 동일 사양 작업을 사용합니다.

또한 tsc 시간과 전체 빌드 시간을 구분해야 합니다. 번들링, 테스트, 이미지 최적화가 대부분을 차지하는 프로젝트라면 타입 검사가 10배 빨라져도 전체 CI는 10배 빨라지지 않습니다. 예를 들어 기존 파이프라인 10분 중 타입 검사가 2분이었다면 이를 12초로 줄여도 전체 시간은 약 8분 12초입니다. 병목을 먼저 측정해야 업그레이드 효과를 정직하게 설명할 수 있습니다.

성능 최적화와 별개로 타입 표현 자체가 복잡해 검사 비용이 커지는 문제는 TypeScript 고급 타입 시스템 가이드에서 다룬 설계 원칙을 함께 적용할 수 있습니다. 템플릿 리터럴 타입과 브랜드 타입을 많이 사용하는 코드라면 Template Literal Types와 Branded Types 실전 패턴의 경계 설정도 참고할 만합니다.

7. 7.0에서 놓치기 쉬운 호환성 변화

설정 파일 외에도 실제 타입 의미가 달라진 부분이 있습니다. 대표적으로 템플릿 리터럴 타입의 문자열 추론이 UTF-16 코드 유닛이 아니라 유니코드 코드 포인트를 자연스럽게 보존합니다.

type HeadTail<S> =
  S extends `${infer Head}${infer Tail}` ? [Head, Tail] : never;

type Emoji = HeadTail<'😀abc'>;
// TypeScript 7: ['😀', 'abc']
// 이전 버전: 서로 분리된 surrogate pair가 추론될 수 있었음

사용자 식별자나 이모지를 타입 수준에서 분해하는 유틸리티는 스냅샷을 갱신하기 전에 의도부터 확인해야 합니다. 새 결과가 대체로 직관적이지만, UTF-16 인덱싱을 의도적으로 모델링한 타입이라면 breaking change입니다.

JavaScript 파일을 checkJs로 검사하는 프로젝트도 별도 회귀 테스트가 필요합니다. 7.0은 JSDoc과 오래된 Closure 스타일 문법 처리 일부를 단순화했습니다. 값 이름을 타입 위치에 직접 쓰는 대신 typeof가 필요하고, Closure 스타일 함수 타입 대신 TypeScript 함수 타입 표기를 사용해야 합니다. .ts 파일만 검사한 결과로 JS 혼합 저장소의 호환성을 판단하면 안 됩니다.

실패 처리를 리팩터링하는 과정에서 새 strict 오류가 대량으로 나타난다면 any로 덮기보다 Result 패턴 기반 TypeScript 오류 처리를 적용해 실패 경계를 명시하는 편이 장기적으로 안전합니다.

8. 프레임워크별 현실적인 전환선

React나 Next.js 프로젝트도 실제 변환을 누가 담당하는지부터 확인해야 합니다. 일반적으로 프레임워크 빌드는 SWC나 Babel이 TypeScript 구문을 제거하고, tsc --noEmit은 별도 타입 검사로 사용됩니다. 이 구조라면 네이티브 CLI를 독립된 검사 작업에 먼저 도입할 수 있습니다. 단, 프레임워크가 지원하는 TypeScript 버전 범위와 자체 플러그인의 API 의존성은 릴리스 노트에서 다시 확인해야 합니다.

Vue·Svelte·Astro·MDX는 파일 안의 TypeScript를 추출하거나 가상 파일로 변환하기 위해 컴파일러 API와 긴밀하게 연결됩니다. TypeScript 7.0 공식 발표는 이 도구들이 아직 7을 활용하지 못할 가능성이 높으며 당분간 6.0을 유지하라고 안내합니다. Angular는 CLI의 빠른 프로젝트 전체 오류 탐지에는 7을 시험할 수 있지만, 템플릿 타입 검사와 에디터 지원은 6 경로가 필요할 수 있습니다.

따라서 저장소 전체에 하나의 “전환 완료” 상태를 붙이기보다 다음처럼 상태를 기록하는 편이 정확합니다.

경로권장 상태
순수 .ts/.tsx CLI 검사TS7 후보 → 필수 게이트
ESLint와 AST 도구TS6 API 유지, 지원 버전 추적
Vue/Svelte/Astro/MDXTS6 유지, 공식 통합 대기
에디터TS7 LSP와 기존 서비스 결과 비교
배포 번들기존 변환기 유지, 타입 검사만 분리 전환

모노레포의 패키지별 책임과 프로젝트 레퍼런스 설계는 프론트엔드 모노레포 아키텍처 가이드와 함께 보면 전환 단위를 정하기 쉽습니다.

9. 롤백 가능한 배포 체크리스트

마이그레이션의 완료 조건은 “로컬에서 빨라졌다”가 아니라 아래 항목을 모두 만족하는 상태입니다.

  • TypeScript 6에서 모든 deprecation을 해결하고 ignoreDeprecations를 제거했다.
  • rootDir, types, module, target을 프로젝트 의도에 맞게 명시했다.
  • CLI, 에디터, 린터, 코드 생성기, 프레임워크 플러그인을 각각 분류했다.
  • 6과 7의 진단 결과가 동일하거나, 차이를 문서화하고 테스트로 고정했다.
  • cold·incremental·watch 빌드의 중앙값과 메모리 사용량을 같은 조건에서 측정했다.
  • CI 코어와 메모리에 맞춰 checkersbuilders 상한을 정했다.
  • TypeScript 6 alias와 기존 lockfile로 즉시 돌아갈 수 있는 롤백 절차가 있다.
  • JS/JSDoc 파일, 유니코드 템플릿 리터럴 타입, 프로젝트 레퍼런스를 회귀 테스트했다.

권장 순서는 TS6 정리 → TS7 관찰용 CI → 진단 동등성 확인 → TS7 필수 게이트 → 에디터 전환 → API 소비 도구 전환입니다. 7.1의 새 API가 나온 뒤에도 도구 생태계가 그 API에 적응하는 시간이 필요하므로, 호환 패키지를 제거하는 날짜를 미리 고정하지 않는 편이 안전합니다.

마치며

TypeScript 7은 대규모 저장소의 피드백 루프를 크게 줄일 수 있는 변화지만, 컴파일러 구현 교체와 API 공백이 동시에 존재하는 독특한 릴리스입니다. 가장 안전한 접근은 성능을 먼저 기대하는 것이 아니라 실행 경계를 먼저 나누는 것입니다. TypeScript 6으로 설정 부채를 제거하고, 네이티브 CLI를 독립된 CI 경로에서 검증하며, API를 사용하는 도구에는 6 호환 계층을 남겨 두면 성능 이득과 운영 안정성을 함께 가져갈 수 있습니다.


참고 자료

작성·검증 정보

이 글은 본문에 연결된 외부 참고 링크 3개와 코드 예제를 바탕으로 작성했습니다. 기술 버전과 지원 범위는 바뀔 수 있으므로 적용 전 연결된 공식 자료의 최신 내용을 함께 확인해 주세요.

발행일 · 작성·정정 원칙 보기

← Waylog Blog 홈으로 돌아가기