Split View: TypeScript 7이 GA됐다 — 8~12배는 진짜지만, 오늘 못 옮기는 사람들이 있다
TypeScript 7이 GA됐다 — 8~12배는 진짜지만, 오늘 못 옮기는 사람들이 있다
- 들어가며 — 7월 8일, tsgo는 그냥 tsc가 됐다
- 숫자부터 정확히 — 무엇을 잰 것인가
- "10배"에는 손잡이가 달려 있다 — --checkers
- 진짜 비용 (1) — 6의 폐기 목록이 전부 하드 에러가 됐다
- 진짜 비용 (2) — API가 없다, 그래서 Vue·MDX·Astro·Svelte는 오늘 못 옮긴다
- 6과 7을 같이 두기 — tsc6와 npm 별칭
- 조용히 바뀐 것들 — JSDoc과 유니코드
- 그래서, 당신은 오늘 옮겨야 하나
- 마치며
- 참고 자료
들어가며 — 7월 8일, tsgo는 그냥 tsc가 됐다
2026년 7월 8일, TypeScript 7.0이 GA됐습니다. 1년 넘게 미리보기로 돌던 Go 네이티브 포트가 정식 릴리스에 들어왔습니다.
지난 1년간 이 프로젝트를 따라온 사람이라면 tsgo라는 이름에 익숙할 겁니다. 별도 패키지(@typescript/native-preview)에서 별도 바이너리로 나이틀리가 나왔고, 기존 tsc와 나란히 돌려 보는 게 표준 절차였습니다. GA에서 그 구도가 사라졌습니다. 공식 발표문에는 tsgo라는 단어가 한 번도 나오지 않습니다. 대신 이렇게 적혀 있습니다 — npm install -D typescript을 하면 "새로운 tsc 실행 파일"이 들어온다고.
즉 네이티브 포트는 옵트인이 아니라 기본값입니다. npm 레지스트리를 직접 확인해 보면 typescript의 latest 태그는 7.0.2이고 발행일은 2026년 7월 8일 — 발표문의 GA 날짜와 정확히 일치합니다. 그리고 @typescript/native-preview의 마지막 발행은 7월 7일, GA 하루 전에서 멈춰 있습니다. 나이틀리는 이제 typescript@next로 넘어왔습니다(현재 7.1.0-dev 계열).
릴리스 타임라인은 이렇게 흘렀습니다 — 베타 4월 21일, RC 6월 18일, GA 7월 8일.
이 글은 "Go 포트가 빠르다"를 다시 설명하는 글이 아닙니다. 그건 TypeScript 6과 tsc-go 포트 편에서 미리보기 시절 기준으로 이미 다뤘고, 솔직히 말하면 그때 예상했던 배포 형태(tsc --go 같은 백엔드 플래그, 한 메이저 버전이 두 컴파일러를 같이 출하하는 그림)와 실제 GA는 다릅니다. 실제로는 메이저 버전 자체가 갈렸습니다 — 6은 JS 구현, 7은 Go 구현입니다. 이 글은 GA에서 확정된 사실만 놓고, 헤드라인 숫자가 가리는 실제 이전 비용을 봅니다.
숫자부터 정확히 — 무엇을 잰 것인가
발표문의 표현은 "10x faster native port"이고, 본문의 조건부 문장은 이렇습니다 — 네이티브 코드 속도, 공유 메모리 멀티스레딩, 여러 최적화가 전체 빌드(full builds)에서 통상 8배에서 12배 사이의 속도 향상을 낸다.
Microsoft가 직접 측정해 공개한 전체 빌드 시간표입니다. 이건 벤더 자체 보고 수치이고, 같은 머신에서 TypeScript 7의 기본 설정으로 잰 것입니다.
코드베이스 TS 6 TS 7 속도 향상
vscode 125.7s 10.6s 11.9x
sentry 139.8s 15.7s 8.9x
bluesky 24.3s 2.8s 8.7x
playwright 12.8s 1.47s 8.7x
tldraw 11.2s 1.46s 7.7x
주목할 점 두 가지. 첫째, 표의 하한은 7.7배로 "8~12배"라는 자기 진술보다 살짝 낮습니다. 둘째, 속도 향상이 코드베이스마다 다릅니다 — vscode의 11.9배와 tldraw의 7.7배는 1.5배 차이입니다. 큰 코드베이스일수록 병렬화 이득이 커지는 경향이 보입니다.
메모리도 같이 공개됐는데, 여기가 오히려 기대를 낮춰야 하는 부분입니다.
코드베이스 TS 6 TS 7 변화
vscode 5.2GB 4.2GB -18%
sentry 4.9GB 4.6GB -6%
bluesky 1.8GB 1.3GB -26%
playwright 1.0GB 0.9GB -11%
tldraw 0.6GB 0.5GB -15%
미리보기 시절에 돌던 "메모리 절반" 이야기와는 다릅니다. 실제 GA 수치는 6%에서 26% 감소이고, sentry는 사실상 거의 그대로입니다. 속도가 한 자릿수 배율로 뛴 것에 비하면 메모리는 완만한 개선입니다. 발표문 자신도 "통상 전체 빌드에 걸쳐 더 적은 총 메모리를 요구한다"는 정도로만 말하고, 그 이상을 주장하지 않습니다.
에디터 쪽 숫자도 있습니다. VS Code 코드베이스에서 에러가 있는 파일을 열었을 때 첫 에러가 보이기까지, 같은 컴퓨터에서 예전에는 약 17.5초가 걸렸고 TypeScript 7에서는 1.3초 미만 — 13배 이상 빠르다는 것입니다.
기업 사례로 보고된 수치들은 한 단계 더 조심해서 읽어야 합니다. 이건 Microsoft가 각 팀에게서 전해 들었다고 밝힌 값들입니다.
- Slack — CI 타입 체크 시간이 약 7.5분에서 1.25분으로. 머지 큐 시간의 40%가 사라졌다고. 이전에는 에디터의 언어 서버 로드 시간 때문에 로컬 개발이 거의 "쓸 수 없는" 수준이라 엔지니어들이 전체 타입 체크를 CI에 맡겼는데, 이제 같은 코드베이스가 몇 초 만에 로드된다고 합니다.
- Canva — 에디터에서 첫 에러를 보기까지 약 58초에서 약 4.8초로.
- Vanta — 가장 큰 프로젝트 하나에서 최대 9배.
- Microsoft News Services 팀 — CI 빌드 대기로 쓰던 시간을 월 400시간 절약.
그리고 안정성 수치. Microsoft는 자체 데이터 인사이트 기준으로 7.0의 새 언어 서버가 6.0 대비 실패하는 언어 서버 커맨드를 80% 이상, 서버 크래시를 60% 이상 줄였다고 밝혔습니다. 이건 텔레메트리 기반 자체 측정이고 외부에서 재현할 수 있는 종류의 숫자는 아닙니다.
"10배"에는 손잡이가 달려 있다 — --checkers
여기가 GA에서 새로 드러난, 그리고 대부분의 요약 기사가 빠뜨린 부분입니다. 저 벤치마크 숫자는 특정 병렬화 설정의 결과입니다.
TypeScript 7.0은 파싱, 타입 체크, 이미터를 병렬로 돌립니다. 파싱과 이미팅은 파일 단위로 거의 독립적이라 병렬화가 잘 먹습니다. 문제는 타입 체크입니다 — 파일 간 의존이 복잡하고, 대부분의 파일이 같은 전역 스코프와 의존성의 타입 정보에 기댑니다. 게다가 타입 체크는 때때로 프로그램 내 정보의 상대적 순서에 의존해서, 결과를 동일하게 유지하려면 항상 같은 순서로 체크해야 합니다.
그래서 TypeScript 7은 고정된 수의 타입 체커 워커를 만듭니다. 각 워커가 자기만의 세계관을 갖고, 공통 작업 일부를 중복해서 하되, 같은 입력이면 항상 동일하게 파일을 나눠 동일한 결과를 냅니다.
기본 워커 수는 4입니다. 앞의 표는 전부 기본값인 --checkers 4로 잰 것이고, 발표문은 같은 머신에서 --checkers 8로 다시 잰 표를 나란히 실었습니다.
코드베이스 TS 6 TS 7 (--checkers 8) 속도 향상
vscode 125.7s 7.51s 16.7x
sentry 139.8s 12.08s 11.6x
bluesky 24.3s 2.01s 12.1x
playwright 12.8s 1.16s 11x
tldraw 11.2s 1.06s 10.6x
체커를 8로 올리면 vscode가 16.7배까지 갑니다. 하지만 이건 공짜가 아닙니다 — 발표문의 표현대로 체커를 늘리면 통상 메모리 사용량 증가라는 대가가 따릅니다. 그리고 결과는 프로젝트와 머신에 따라 달라집니다.
방향은 반대로도 갑니다. CPU 코어와 메모리가 적은 환경 — 발표문이 직접 예로 든 게 CI 러너입니다 — 에서는 오히려 이 값을 낮춰서 불필요한 오버헤드를 피하는 편이 나을 수 있습니다. --checkers 1까지 지정할 수 있고, 그러면 타입 체크가 사실상 단일 스레드가 되면서 중복 작업이 사라집니다.
여기서 실무적으로 가장 중요한 문장이 나옵니다.
드문 경우지만,
--checkers수를 바꾸면 순서 의존적인 결과가 드러날 수 있습니다.
즉 체커 수가 진단 결과에 영향을 줄 수 있다는 것을 팀이 직접 인정한 것입니다. 발표문의 권고는 빌드 환경 전반에 고정된 체커 수를 지정해서 모두가 같은 결과를 받게 하라는 것이고, 다만 그건 팀 재량이라고 덧붙입니다. 로컬은 8, CI는 2 같은 식으로 제각각 두면 "내 머신에서는 통과하는데 CI에서는 에러"가 나올 여지가 원리상 열려 있다는 뜻입니다. 저라면 tsconfig.json이든 CI 스크립트든 한 곳에 못을 박아 두겠습니다.
관련 플래그가 둘 더 있습니다. --builders는 --build 모드에서 동시에 돌릴 프로젝트 참조 빌더 수를 조절합니다(모노레포용). 주의할 건 --checkers와 곱셈으로 작용한다는 점입니다 — 발표문의 예시 그대로, --checkers 4 --builders 4는 최대 16개의 타입 체커가 동시에 도는 걸 허용하고, 이건 과할 수 있습니다. --singleThreaded는 병렬화를 아예 끕니다(디버깅, 6과 7의 성능 비교, 외부에서 병렬 빌드를 조율하는 경우, 자원이 아주 빠듯한 환경용). --checkers와 --builders는 현재 실험적(experimental) 플래그로 소개돼 있습니다.
--builders는 --checkers와 달리 수를 바꿔도 결과가 달라지지 않아야 한다고 명시돼 있습니다. 대신 프로젝트 참조 빌드는 근본적으로 프로젝트 의존 그래프에 병목이 걸립니다.
진짜 비용 (1) — 6의 폐기 목록이 전부 하드 에러가 됐다
이제 돈을 내는 부분입니다.
호환성 자체는 좋습니다. 발표문의 조건부 문장은 이렇습니다 — stableTypeOrdering 플래그를 켜고 ignoreDeprecations 플래그를 설정하지 않은 상태에서 TypeScript 6.0으로 깨끗하게 컴파일되는 코드는 사실상 무엇이든 7.0에서 동일하게 컴파일돼야 한다.
문제는 저 전제입니다. 7.0은 6.0의 새 기본값을 그대로 채택하고, 6.0에서 폐기 예고된 플래그와 구문에 대해 하드 에러를 냅니다. 발표문 스스로 인정하듯 "6.0은 상대적으로 아직 새롭고, 많은 프로젝트가 그 새 동작에 적응해야" 합니다. 그래서 공식 권고는 7로 바로 뛰지 말고 6.0을 먼저 도입해서 전환을 쉽게 만들라는 것입니다.
기본값 변경부터 봅시다.
strict -> 기본 true
module -> 기본 esnext
target -> esnext 바로 앞의 안정 ECMAScript 버전
noUncheckedSideEffectImports -> 기본 true
libReplacement -> 기본 false
stableTypeOrdering -> 기본 true, 그리고 끌 수 없음
rootDir -> 기본 ./ (내부 소스 디렉터리는 명시해야 함)
types -> 기본 [] (예전 동작은 ["*"])
발표문이 "가장 놀랄 만한" 변경으로 꼽은 건 rootDir과 types 둘입니다. 둘 다 완화는 쉽습니다. tsconfig.json이 src 같은 디렉터리 바깥에 있는 프로젝트는 디렉터리 구조를 유지하려면 rootDir을 명시하면 됩니다.
{
"compilerOptions": {
"rootDir": "./src"
},
"include": ["./src"]
}
types 쪽은 전역 선언에 의존하는 프로젝트가 필요한 걸 직접 나열해야 합니다.
{
"compilerOptions": {
"types": ["node", "jest"]
}
}
무해해 보이지만 이게 조용한 지뢰입니다. types 기본값이 []가 되면 자동 탐색이 꺼집니다 — 지금까지 @types/node나 @types/jest를 설치만 해 두고 자동으로 주워 오길 기대했다면, 7에서는 갑자기 전역 심볼이 없다는 에러가 쏟아집니다. 코드가 잘못된 게 아니라 설정이 바뀐 것이고, 고치는 법도 한 줄이지만, 큰 모노레포에서 이걸 패키지마다 밟아 나가는 건 지루한 작업입니다.
strict이 기본 true가 된 것도 마찬가지입니다. 지금까지 non-strict으로 살아온 레거시 코드베이스라면 이건 "컴파일러를 바꾸는 일"이 아니라 "타입을 다시 쓰는 일"입니다. 8배 빠른 컴파일러를 얻으려고 몇 달치 strictNullChecks 작업을 선불로 치러야 하는 상황이 생길 수 있습니다.
그리고 아예 없어진 것들 — 무동작(no-op)이 아니라 하드 에러입니다.
target: es5지원 종료downlevelIteration지원 종료moduleResolution: node및node10지원 종료 (nodenext또는bundler권장)module: amd,umd,systemjs,none지원 종료 (esnext또는preserve권장)baseUrl지원 종료 (paths를 프로젝트 루트 기준 상대 경로로 갱신)moduleResolution: classic지원 종료esModuleInterop과allowSyntheticDefaultImports를false로 설정 불가alwaysStrict은 항상 참으로 간주되고false로 설정 불가- 네임스페이스 선언에서
module키워드 사용 불가 - import에서
asserts키워드 사용 불가 — ECMAScript import attribute 구문에 맞춰with를 써야 함 skipDefaultLibCheck하에서/// <reference no-default-lib />지시문이 더 이상 존중되지 않음- 현재 디렉터리에
tsconfig.json이 있으면 명령줄 빌드가 파일 경로를 받을 수 없음 (--ignoreConfig플래그를 명시하지 않는 한)
이 목록에서 실무를 가장 아프게 할 건 baseUrl과 target: es5입니다. baseUrl은 오래된 프로젝트의 절대 경로 import에 광범위하게 깔려 있고, target: es5는 아직 구형 브라우저를 지원해야 하는 팀에게는 협상 불가능한 요구일 수 있습니다. es5가 필요하면 7은 당신의 것이 아닙니다. 이건 설정을 고쳐서 넘어갈 수 있는 종류의 벽이 아닙니다.
마지막 항목도 의외로 잘 밟힙니다. npx tsc src/foo.ts 같은 걸 스크립트에 넣어 둔 팀이 꽤 있는데, 프로젝트 루트에 tsconfig.json이 있으면 이제 그냥 에러입니다.
진짜 비용 (2) — API가 없다, 그래서 Vue·MDX·Astro·Svelte는 오늘 못 옮긴다
이게 GA 발표문에서 가장 중요한데 가장 적게 인용되는 부분입니다.
TypeScript 7.0이 나왔지만, API를 출하하지 않습니다.
프로그래밍 API가 없습니다. 7.1에서 새로운(그리고 다른) API를 출하할 것으로 예상한다고 적혀 있고, 그때까지는 6과 7을 나란히 돌릴 수 있게 하는 걸 우선순위로 삼았다고 합니다.
여파는 직접적입니다. 발표문의 "TypeScript and Embedded Languages" 절을 그대로 옮기면 — Vue, MDX, Astro, Svelte 등을 쓰는 워크플로는 아직 TypeScript 7을 활용하지 못할 가능성이 큽니다. Angular처럼 템플릿 내부의 특화된 타입 체크도 마찬가지입니다. 이유는 7이 아직 안정적인 프로그래밍 API를 노출하지 않아서, TypeScript를 자기 컴파일러와 언어 서비스에 임베드하는 도구들 — Volar 같은 — 이 현재로서는 TypeScript 6.0에만 의존할 수 있기 때문입니다.
이건 "조금 느릴 수 있다"가 아니라 못 쓴다입니다. 프런트엔드 생태계의 상당 지분이 여기 걸립니다. Vue 팀, Astro 팀, Svelte 팀, 그리고 MDX 기반 문서/블로그 파이프라인 전부 Volar 위에 서 있습니다.
권고안은 이렇게 나뉩니다.
- 언어 서버 플러그인이 필요 없는 시나리오에서 7을 쓰라 — 이게 기본 권고입니다.
- Angular — CLI에서
tsc로 빠른 프로젝트 전역 에러 탐지를 하고, 에디터 지원은 6.0을 쓰는 조합이 가능합니다. 즉 반쪽은 가져갈 수 있습니다. - Vue, MDX, Astro, Svelte 등 — 당분간 6.0을 계속 써야 합니다. VS Code에서는 "Disable TypeScript 7 Language Server" 커맨드로 6.0으로 되돌릴 수 있습니다.
Microsoft는 이걸 "특정 시점의 문제(point-in-time issue)"로 보며 해결책 제공을 약속했고, 해당 프로젝트 메인테이너들과 적극 협력하겠다고 밝혔습니다. 믿을 만한 약속이라고 봅니다 — 다만 약속은 오늘의 빌드를 고쳐 주지 않습니다. 7.1의 새 API가 나오고, Volar가 거기 맞춰 포팅되고, Vue/Astro/Svelte 툴링이 각각 그걸 채택하는 데까지는 릴리스 사이클이 여러 번 돕니다. 발표문 자신이 밝힌 릴리스 주기가 3~4개월마다이니, 여기에 다운스트림 채택 시간이 더 붙습니다.
6과 7을 같이 두기 — tsc6와 npm 별칭
그래서 현실적인 답은 대개 "둘 다 둔다"입니다. 이걸 위해 Microsoft가 호환 패키지를 새로 냈습니다.
@typescript/typescript6은 tsc6이라는 실행 파일을 제공합니다. 그래서 자기 tsc 바이너리를 갖고 오는 7.0을 이름 충돌 없이 나란히 설치할 수 있습니다. 이 패키지는 TypeScript 6.0 API를 다시 export하기도 해서, tsc는 7로 쓰면서 다른 툴링은 계속 6.0에 의존하게 둘 수 있습니다. npm 레지스트리에서 확인해 보면 이 패키지의 latest는 6.0.2이고 bin 항목은 정확히 tsc6 하나입니다.
typescript-eslint 같은 도구는 peer dependency를 통해 typescript에서 직접 import하길 기대하기 때문에, 권장 방법은 npm 별칭입니다.
npm install -D typescript@npm:@typescript/typescript6
다만 이렇게만 하면 tsc6 실행 파일만 남습니다. 7.0의 tsc도 같이 얻으려면 별칭을 하나 더 겁니다.
{
"devDependencies": {
"@typescript/native": "npm:typescript@^7.0.2",
"typescript": "npm:@typescript/typescript6@^6.0.2"
}
}
이러면 npx tsc는 7.0으로 동작하고, typescript를 import하는 도구들은 6.0을 봅니다.
솔직히 말하면 이건 우아한 해법이 아닙니다. package.json에 별칭 두 개가 얽혀 있고, typescript라는 이름이 실제로는 6을 가리키는 상태는 처음 보는 사람에게 확실히 헷갈립니다. 하지만 typescript-eslint를 쓰면서 tsc는 빠르게 돌리고 싶다면 — 그러니까 현실의 상당수 프로젝트라면 — 지금은 이게 공식 경로입니다.
조용히 바뀐 것들 — JSDoc과 유니코드
성능 헤드라인에 가려졌지만 실제로 코드를 깨뜨릴 수 있는 변경이 둘 더 있습니다.
JavaScript 지원이 재작업됐습니다. 원래 TypeScript는 JSDoc 주석과 특정 코드 패턴을 인식해서 JS 파일을 지원했는데, 그게 종종 Closure나 JSDoc 문서 생성 도구가 이해하던 것에 기반한 특수 케이스 덩어리였습니다. 7.0은 이걸 .ts 파일 분석 방식과 일관되게 다시 짰습니다. 결과적으로 사라진 것들이 있습니다.
- 타입이 와야 할 자리에 값을 쓸 수 없음 —
typeof someValue로 써야 함 @enum이 더 이상 특별 취급되지 않음- 단독
?를 타입으로 쓸 수 없음 —any를 쓸 것 @class가 함수를 생성자로 만들지 않음 — 클래스 선언을 쓸 것- 후위
!미지원 - 타입 이름은
@typedef태그 안에서 정의해야 함 (식별자 옆에 두는 형태는 불가) - Closure 스타일 함수 구문 미지원 — TypeScript 축약형을 쓸 것
this를 별칭으로 두거나 함수의 프로토타입을 통째로 재할당하는 패턴도 특별 취급이 사라졌습니다. JSDoc으로 타입을 붙인 큰 JS 코드베이스를 갖고 있다면 여기가 진짜 이전 작업입니다. TypeScript 팀은 6.0과 7.0의 차이를 담은 CHANGES.md 파일을 따로 관리하고 있다고 밝혔고, JS 지원은 아직 유동적(in flux)이라고 표현합니다.
템플릿 리터럴 타입이 유니코드 코드 포인트를 보존합니다.
type HeadTail<S> = S extends `${infer Head}${infer Tail}` ? [Head, Tail] : never;
type Result = HeadTail<"😀abc">;
// 7.0에서: ["😀", "abc"]
// 이전: ["\ud83d", "\ude00abc"]
예전에는 JavaScript의 UTF-16 인덱싱 동작을 따라 서로게이트 쌍을 반으로 쪼갰습니다. 기술적으로는 JS 인덱싱과 일관됐지만 대개 의도한 바가 아니었고, 의미 없는 짝 없는 서로게이트를 담은 문자열 리터럴 타입이 나올 수 있었습니다. 새 동작은 for...of로 순회하거나 스프레드할 때의 직관과 같습니다.
발표문은 이걸 UTF-16 코드 유닛을 의도적으로 모델링한 타입 레벨 문자열 조작에 대한 파괴적 변경이라고 정직하게 라벨합니다 — 일부 문자열 Length 유틸리티가 예로 나옵니다. 타입 레벨 문자열 프로그래밍을 깊게 하는 라이브러리를 쓰거나 만든다면 확인이 필요합니다.
한 가지 더. --watch 모드가 완전히 다시 만들어졌습니다. Parcel 번들러의 파일 워처를 Go로 포팅한 게 새 기반입니다(원래 C++이라 전체 C++ 툴체인이 필요했던 걸 최소한의 어셈블리 심으로 Go에 옮겼습니다). Go 표준 라이브러리에 파일 감시 API가 없고, 폴링 기반 해법은 node_modules 의존성이 많은 대형 프로젝트에서 너무 비쌌다는 게 이유입니다. 발표문은 플랫폼 전반에서 --watch의 자원 사용이 크게 개선됐다고 보고합니다.
그래서, 당신은 오늘 옮겨야 하나
정리하면 이렇게 갈립니다.
오늘 옮겨서 값을 하는 경우
- 이미 TypeScript 6.0을 쓰고 있고,
stableTypeOrdering을 켠 채ignoreDeprecations없이 깨끗하게 빌드된다 — 이게 공식 호환성 문장이 보장하는 정확한 조건입니다. 이 경우 이전은 대체로 무난합니다. - 순수
.ts/.tsx코드베이스이고 Volar 계열 임베디드 언어 툴링을 쓰지 않는다. - CI 타입 체크가 실제 병목이다 — 8배는 여기서 바로 현금화됩니다.
- 에디터 응답성이 팀의 실질적 고통이다.
아직 못 옮기는 경우
- Vue, MDX, Astro, Svelte를 쓴다 — 선택의 문제가 아닙니다. 7.1의 API와 그 뒤의 Volar 포팅을 기다려야 합니다.
- Angular — 반쪽만 가능합니다. CLI 타입 체크는 7, 에디터는 6.
target: es5가 필요하다 — 벽입니다.- 아직 TypeScript 5.x이고 non-strict이다 — 7로 바로 뛰지 마십시오. 6을 먼저 거치는 게 공식 권고이고, 이유가 있습니다. 폐기 목록을 한 번에 다 밟는 대신 6에서 경고로 받아 가며 정리할 수 있습니다.
- typescript-eslint 등 API 의존 툴링이 핵심 워크플로다 — 앞의 별칭 조합으로 가능은 하지만, 그 복잡도를 감수할 가치가 있는지는 팀이 판단할 문제입니다.
그리고 순서에 대한 조언 하나. 옮긴다면 --checkers 값을 명시적으로 고정하고 시작하십시오. 로컬과 CI가 서로 다른 기본 병렬도로 도는 상태에서 순서 의존적 진단 차이를 만나면, 그건 디버깅하기 가장 싫은 종류의 버그입니다. 팀이 직접 "드문 경우지만 드러날 수 있다"고 적어 둔 이상, 값을 못 박는 비용은 한 줄이고 안 박는 비용은 반나절입니다.
마치며
TypeScript 7.0의 성능 이야기는 진짜입니다. 벤더 자체 보고이긴 하지만 재현 가능한 오픈소스 코드베이스로 측정됐고, 조건(기본 --checkers 4, 전체 빌드)도 공개돼 있고, --checkers 8 표까지 같이 실어서 숫자가 설정에 따라 움직인다는 걸 스스로 드러냈습니다. 이 정도면 벤더 벤치마크로서는 정직한 축입니다. Slack의 7.5분 → 1.25분 같은 수치가 재현된다면, 큰 코드베이스에서 이건 삶의 질 문제입니다.
하지만 헤드라인은 "10배 빨라졌다"이고, 실제 이야기는 "10배 빨라졌고, 그 대가로 6의 폐기 목록을 전부 청산해야 하며, 프런트엔드 생태계의 큰 조각은 API가 나올 때까지 초대받지 못했다"입니다.
그래서 저는 이걸 이렇게 봅니다 — 7.0은 완성된 이주가 아니라 시작된 이주입니다. 7.1이 API를 갖고 나오고 Volar가 그 위에 서기 전까지, 이 생태계는 당분간 6과 7로 갈라져 삽니다. @typescript/typescript6과 tsc6이라는 호환 패키지가 존재한다는 사실 자체가 그걸 인정하는 것입니다. Microsoft도 이걸 알고 있고, 그래서 발표문 마지막에 "7.1로 어떤 간극이든 메워 커뮤니티를 앞으로 데려가고 싶다"고 적었습니다.
당신이 순수 TS 코드베이스라면 오늘이 좋은 날입니다. Vue나 Astro 위에 서 있다면, 이번 릴리스는 당신 것이 아직 아닙니다 — 그리고 그건 당신이 뭘 잘못해서가 아닙니다.
참고 자료
- Announcing TypeScript 7.0 (Microsoft, 2026-07-08) — 이 글의 모든 수치·인용의 출처
- Announcing TypeScript 7.0 RC (2026-06-18)
- Announcing TypeScript 7.0 Beta (2026-04-21)
- npm — typescript — GA 시점
latest는 7.0.2,next는 7.1.0-dev 계열 - npm — @typescript/typescript6 —
tsc6실행 파일을 제공하는 6.0 호환 패키지 - microsoft/typescript-go — 네이티브 포트 저장소
- TypeScript 6과 tsc-go 포트 — 미리보기 시절 기준 관련 글
TypeScript 7 Is GA — the 8-12x Is Real, but Some People Cannot Move Today
- Introduction — July 8: tsgo Just Became tsc
- Getting the Numbers Right — What Was Actually Measured
- The "10x" Has a Dial — --checkers
- The Real Cost (1) — Everything TypeScript 6 Deprecated Is Now a Hard Error
- The Real Cost (2) — No API, So Vue, MDX, Astro, and Svelte Cannot Move Today
- Running 6 and 7 Side by Side — tsc6 and npm Aliases
- Quietly Changed — JSDoc and Unicode
- So, Should You Move Today?
- Closing
- References
Introduction — July 8: tsgo Just Became tsc
On July 8, 2026, TypeScript 7.0 went GA. The Go native port, which had been running in preview for over 1 year, landed in a full release.
If you have followed this project over the past 1 year, the name tsgo will be familiar. Nightlies shipped as a separate binary from a separate package (@typescript/native-preview), and running it side by side with the existing tsc was the standard procedure. That arrangement is gone at GA. The word tsgo does not appear once in the official announcement. Instead, it says that running npm install -D typescript gets you "a new tsc executable."
In other words, the native port is not opt-in anymore — it is the default. Checking the npm registry directly, the latest tag for typescript is 7.0.2, published on 2026-07-08 — exactly matching the GA date in the announcement. And the last publish of @typescript/native-preview stopped at July 7, one day before GA. Nightlies have now moved to typescript@next (currently in the 7.1.0-dev line).
The release timeline ran as follows: beta on April 21, RC on June 18, GA on July 8.
This post is not here to re-explain that "the Go port is fast." That was already covered in TypeScript 6 and the tsc-go Port, back in the preview era, and honestly, the shipping shape we expected back then — a backend flag like tsc --go, one major version shipping two compilers side by side — is not what GA turned out to be. What actually happened is that the major version itself split — 6 is the JS implementation, 7 is the Go implementation. This post sticks to what is confirmed at GA and looks at the real migration costs the headline number hides.
Getting the Numbers Right — What Was Actually Measured
The announcement's own phrase is "10x faster native port," and the qualified sentence in the body reads: native code speed, shared-memory multithreading, and various optimizations typically produce an 8x to 12x speedup on full builds.
Here is the full-build timing table Microsoft measured and published directly. This is a vendor-reported figure, measured on the same machine using TypeScript 7's default settings.
Codebase TS 6 TS 7 Speedup
vscode 125.7s 10.6s 11.9x
sentry 139.8s 15.7s 8.9x
bluesky 24.3s 2.8s 8.7x
playwright 12.8s 1.47s 8.7x
tldraw 11.2s 1.46s 7.7x
Two things stand out. First, the table's low end is 7.7x, slightly below the announcement's own "8-12x" claim. Second, the speedup varies by codebase — vscode's 11.9x and tldraw's 7.7x are 1.5x apart. Larger codebases appear to see bigger parallelization gains.
Memory numbers were published alongside these, and this is actually where you should temper expectations.
Codebase TS 6 TS 7 Change
vscode 5.2GB 4.2GB -18%
sentry 4.9GB 4.6GB -6%
bluesky 1.8GB 1.3GB -26%
playwright 1.0GB 0.9GB -11%
tldraw 0.6GB 0.5GB -15%
This is not the "half the memory" story that circulated during preview. The actual GA figures show a 6% to 26% reduction, and sentry is essentially flat. Compared to speed jumping by a single-digit multiplier, memory is a modest improvement. The announcement itself only claims that it "typically requires less total memory across full builds," and does not claim more than that.
There are editor-side numbers too. For the VS Code codebase, the time to see the first error after opening a file with an error, on the same machine, used to take about 17.5 seconds; on TypeScript 7 it is under 1.3 seconds — more than a 13x speedup.
Numbers reported from enterprise case studies need to be read with an extra degree of caution. These are figures Microsoft says it heard secondhand from each team.
- Slack — CI type-check time went from about 7.5 minutes to 1.25 minutes. Reportedly, 40% of merge-queue time disappeared. Previously, editor language-server load times made local development nearly "unusable," so engineers offloaded full type checking to CI; now the same codebase reportedly loads in seconds.
- Canva — time to see the first error in the editor went from about 58 seconds to about 4.8 seconds.
- Vanta — up to 9x on its single largest project.
- The Microsoft News Services team — saved 400 hours a month that used to go into waiting on CI builds.
There is also a stability figure. Based on its own data insights, Microsoft says 7.0's new language server cut failed language-server commands by over 80% and server crashes by over 60%, compared to 6.0. This is a telemetry-based self-measurement and not the kind of figure an outsider can reproduce.
The "10x" Has a Dial — --checkers
This is the part that only came out at GA, and that most summary articles skip. Those benchmark numbers are the result of one specific parallelization setting.
TypeScript 7.0 runs parsing, type checking, and emitting in parallel. Parsing and emitting are nearly independent per file, so they parallelize well. The problem is type checking — cross-file dependencies are complex, and most files lean on the same global scope and the same dependencies' type information. On top of that, type checking sometimes depends on the relative order of information within the program, so keeping results consistent requires always checking in the same order.
So TypeScript 7 spins up a fixed number of type-checker workers. Each worker keeps its own view of the world and duplicates some shared work, but for the same input it always splits files the same way and produces the same result.
The default worker count is 4. The tables above were all measured with the default --checkers 4, and the announcement runs a second table on the same machines with --checkers 8.
Codebase TS 6 TS 7 (--checkers 8) Speedup
vscode 125.7s 7.51s 16.7x
sentry 139.8s 12.08s 11.6x
bluesky 24.3s 2.01s 12.1x
playwright 12.8s 1.16s 11x
tldraw 11.2s 1.06s 10.6x
Bumping checkers to 8 takes vscode as high as 16.7x. But it is not free — in the announcement's own words, raising the checker count typically comes at the cost of increased memory usage. And results vary by project and machine.
It goes the other direction too. In environments with fewer CPU cores and less memory — the announcement's own example is a CI runner — it can actually be better to lower this value to avoid unnecessary overhead. You can set it as low as --checkers 1, at which point type checking becomes effectively single-threaded and the duplicated work disappears.
Here comes the single most practically important sentence.
In rare cases, changing the
--checkerscount can surface order-dependent results.
In other words, the team is directly admitting that the checker count can affect diagnostic results. The announcement's recommendation is to pin a fixed checker count across your whole build environment so everyone gets the same result, while adding that it is ultimately up to the team. If you leave it inconsistent — 8 locally, 2 in CI, say — that opens the door, in principle, to a "passes on my machine, errors in CI" situation. Personally, I would nail this down in one place, whether that is tsconfig.json or a CI script.
There are two more related flags. --builders controls how many project-reference builders run concurrently in --build mode (for monorepos). The thing to watch is that it multiplies with --checkers — straight from the announcement's own example, --checkers 4 --builders 4 allows up to 16 type checkers running concurrently, which can be excessive. --singleThreaded turns off parallelization entirely (for debugging, comparing 6 vs 7 performance, cases where an external tool orchestrates parallel builds, or very resource-constrained environments). --checkers and --builders are currently introduced as experimental flags.
Unlike --checkers, --builders is explicitly documented to not change results when its count changes. Instead, project-reference builds are fundamentally bottlenecked by the project dependency graph.
The Real Cost (1) — Everything TypeScript 6 Deprecated Is Now a Hard Error
Now for the part where you pay.
Compatibility itself is good. The announcement's qualified sentence reads: with the stableTypeOrdering flag on and the ignoreDeprecations flag unset, virtually anything that compiles cleanly under TypeScript 6.0 should compile identically under 7.0.
The problem is that premise. 7.0 adopts 6.0's new defaults wholesale, and turns flags and syntax that 6.0 flagged as deprecated into hard errors. As the announcement itself concedes, "6.0 is relatively new, and many projects still need to adapt to its new behavior." So the official recommendation is not to jump straight to 7, but to adopt 6.0 first to ease the transition.
Let us start with the default changes.
strict -> defaults to true
module -> defaults to esnext
target -> the latest stable ECMAScript version just before esnext
noUncheckedSideEffectImports -> defaults to true
libReplacement -> defaults to false
stableTypeOrdering -> defaults to true, and cannot be turned off
rootDir -> defaults to ./ (an inner source directory must be specified explicitly)
types -> defaults to [] (the old behavior was ["*"])
The two changes the announcement calls out as the "most surprising" are rootDir and types. Both are easy to work around. Projects whose tsconfig.json sits outside a directory like src can just set rootDir explicitly to preserve their directory structure.
{
"compilerOptions": {
"rootDir": "./src"
},
"include": ["./src"]
}
For types, projects that rely on global declarations now have to list what they need explicitly.
{
"compilerOptions": {
"types": ["node", "jest"]
}
}
This looks harmless, but it is a quiet landmine. Once types defaults to [], automatic discovery turns off — if you had been relying on installing @types/node or @types/jest and having them picked up automatically, 7 suddenly floods you with errors about missing global symbols. The code is not wrong, the configuration changed, and the fix is a one-liner — but walking through this package by package in a large monorepo is tedious work.
strict defaulting to true is the same story. For a legacy codebase that has lived non-strict up to now, this is not "swapping compilers" — it is "rewriting your types." You could end up paying months of strictNullChecks work up front just to get an 8x-faster compiler.
And then there are the things that are simply gone — not no-ops, hard errors.
- Support for
target: es5ends - Support for
downlevelIterationends - Support for
moduleResolution: nodeandnode10ends (nodenextorbundlerrecommended) - Support for
module: amd,umd,systemjs, andnoneends (esnextorpreserverecommended) - Support for
baseUrlends (updatepathsto be relative to the project root) - Support for
moduleResolution: classicends esModuleInteropandallowSyntheticDefaultImportscan no longer be set tofalsealwaysStrictis always treated as true and can no longer be set tofalse- The
modulekeyword can no longer be used in namespace declarations - The
assertskeyword can no longer be used on imports — usewithinstead, matching ECMAScript import attributes syntax - Under
skipDefaultLibCheck, the/// <reference no-default-lib />directive is no longer honored - If a
tsconfig.jsonexists in the current directory, command-line builds can no longer accept file paths (unless you pass--ignoreConfigexplicitly)
The two items on this list that will hurt the most in practice are baseUrl and target: es5. baseUrl is baked broadly into absolute-path imports in older projects, and target: es5 can be a non-negotiable requirement for teams that still have to support legacy browsers. If you need es5, 7 is not for you. This is not the kind of wall you can configure your way past.
That last item is also surprisingly easy to trip over. Plenty of teams have something like npx tsc src/foo.ts baked into a script, and if there is a tsconfig.json at the project root, that is now simply an error.
The Real Cost (2) — No API, So Vue, MDX, Astro, and Svelte Cannot Move Today
This is the most important part of the GA announcement, and the least-quoted.
TypeScript 7.0 is here, but it ships no API.
There is no programming API. The announcement says a new (and different) API is expected to ship in 7.1, and that until then, the priority was making it possible to run 6 and 7 side by side.
The fallout is direct. Carrying over the announcement's "TypeScript and Embedded Languages" section verbatim: workflows using Vue, MDX, Astro, Svelte, and similar tools are likely unable to take advantage of TypeScript 7 yet. The same goes for specialized in-template type checking like Angular's. The reason is that 7 does not yet expose a stable programming API, so tools that embed TypeScript in their own compilers and language services — like Volar — can currently only depend on TypeScript 6.0.
This is not "might be a bit slow" — it is cannot use it. A substantial share of the frontend ecosystem is caught here. The Vue team, the Astro team, the Svelte team, and every MDX-based docs/blog pipeline all sit on top of Volar.
The recommendations split three ways.
- Use 7 in scenarios that do not need a language-server plugin — this is the default recommendation.
- Angular — you can combine fast project-wide error detection via
tscin the CLI with editor support running on 6.0. In other words, you can take half the win. - Vue, MDX, Astro, Svelte, and the like — you have to keep using 6.0 for now. In VS Code, the "Disable TypeScript 7 Language Server" command reverts you to 6.0.
Microsoft frames this as a "point-in-time issue," has promised a fix, and says it will work actively with the maintainers of the affected projects. I take that as a credible commitment — but a commitment does not fix today's build. It will take several release cycles before 7.1's new API ships, Volar ports to it, and Vue/Astro/Svelte tooling each adopts it in turn. The announcement itself states a release cadence of every 3 to 4 months, and downstream adoption time stacks on top of that.
Running 6 and 7 Side by Side — tsc6 and npm Aliases
So the realistic answer is usually "keep both." Microsoft shipped a new compatibility package for exactly this.
@typescript/typescript6 provides an executable named tsc6. That lets you install it side by side with 7.0 — which brings its own tsc binary — without a naming collision. The package also re-exports the TypeScript 6.0 API, so you can run tsc on 7 while keeping other tooling dependent on 6.0. Checking the npm registry, this package's latest is 6.0.2 and its bin entry is exactly one: tsc6.
Tools like typescript-eslint expect to import directly from typescript via a peer dependency, so the recommended approach is an npm alias.
npm install -D typescript@npm:@typescript/typescript6
But doing only that leaves you with just the tsc6 executable. To also get 7.0's tsc, add one more alias.
{
"devDependencies": {
"@typescript/native": "npm:typescript@^7.0.2",
"typescript": "npm:@typescript/typescript6@^6.0.2"
}
}
With this, npx tsc runs on 7.0, while tools that import typescript see 6.0.
Honestly, this is not an elegant solution. Two intertwined aliases in package.json, with the name typescript actually pointing at 6 — that is genuinely confusing to anyone seeing it for the first time. But if you use typescript-eslint and still want tsc to run fast — which describes a good chunk of real-world projects — this is the official path for now.
Quietly Changed — JSDoc and Unicode
Two more changes are overshadowed by the performance headlines but can actually break code.
JavaScript support was reworked. TypeScript originally supported JS files by recognizing JSDoc comments and specific code patterns, which was often a pile of special cases based on what Closure or JSDoc documentation-generation tools understood. 7.0 rewrote this to be consistent with how .ts files are analyzed. As a result, some things went away.
- You can no longer write a value where a type is expected — use
typeof someValueinstead @enumis no longer given special treatment- A bare
?can no longer be used as a type — useany @classno longer turns a function into a constructor — use a class declaration- Trailing
!is no longer supported - Type names must be defined inside the
@typedeftag (placing them next to an identifier is no longer allowed) - Closure-style function syntax is no longer supported — use the TypeScript shorthand
Patterns like aliasing this or wholesale reassigning a function's prototype have also lost their special treatment. If you have a large JS codebase typed with JSDoc, this is where the real migration work is. The TypeScript team says it maintains a separate CHANGES.md file capturing the differences between 6.0 and 7.0, and describes JS support as still "in flux."
Template literal types now preserve Unicode code points.
type HeadTail<S> = S extends `${infer Head}${infer Tail}` ? [Head, Tail] : never;
type Result = HeadTail<"😀abc">;
// On TS 7.0: ["😀", "abc"]
// Before: ["\ud83d", "\ude00abc"]
Previously, following JavaScript's UTF-16 indexing behavior, surrogate pairs were split in half. That was technically consistent with JS indexing, but usually not what anyone intended, and it could produce string literal types holding meaningless unpaired surrogates. The new behavior matches the intuition you get from iterating with for...of or spreading.
The announcement honestly labels this as a breaking change for type-level string manipulation that deliberately models UTF-16 code units — some string Length utilities are given as an example. If you use or build libraries that do heavy type-level string programming, you need to check this.
One more thing. --watch mode has been completely rebuilt. The new foundation is a Go port of the Parcel bundler's file watcher (it was originally C++, requiring a whole C++ toolchain, and has been moved to Go with a minimal assembly shim). The reason is that the Go standard library has no file-watching API, and a polling-based solution was too expensive for large projects with heavy node_modules dependencies. The announcement reports significantly improved resource usage for --watch across platforms.
So, Should You Move Today?
Here is how it breaks down.
When moving today pays off
- You are already on TypeScript 6.0 and build cleanly with
stableTypeOrderingon and noignoreDeprecations— this is exactly the condition the official compatibility statement guarantees. In this case, migration is generally painless. - Your codebase is pure
.ts/.tsxand does not use Volar-family embedded-language tooling. - CI type checking is a real bottleneck — the 8x pays off directly here.
- Editor responsiveness is a real pain point for your team.
When you cannot move yet
- You use Vue, MDX, Astro, or Svelte — this is not a matter of choice. You have to wait for 7.1's API and the Volar port that follows it.
- Angular — only half of it is possible. CLI type checking on 7, editor on 6.
- You need
target: es5— this is a wall. - You are still on TypeScript 5.x and non-strict — do not jump straight to 7. Going through 6 first is the official recommendation, and there is a reason for it: instead of hitting the entire deprecation list at once, you can work through it as warnings under 6.
- API-dependent tooling like typescript-eslint is core to your workflow — the alias combination above makes it possible, but whether that complexity is worth taking on is a call your team has to make.
One piece of sequencing advice. If you do move, start by explicitly pinning your --checkers value. If local and CI run at different default parallelism levels and you run into an order-dependent diagnostic difference, that is the exact kind of bug nobody wants to debug. Given that the team has written, in its own words, that it "can surface in rare cases," pinning the value costs one line, and not pinning it costs half a day.
Closing
TypeScript 7.0's performance story is real. It is vendor self-reported, but it was measured against reproducible open-source codebases, the conditions (default --checkers 4, full builds) are disclosed, and the announcement even ran a --checkers 8 table alongside it, which itself reveals that the numbers move with configuration. As vendor benchmarks go, this is on the honest end. If numbers like Slack's 7.5 minutes to 1.25 minutes reproduce, that is a quality-of-life issue on a large codebase.
But the headline is "10x faster," and the real story is "10x faster, at the cost of clearing 6's entire deprecation list, with a large piece of the frontend ecosystem not invited until the API ships."
So here is how I see it — 7.0 is a migration that has started, not one that is finished. Until 7.1 ships with an API and Volar builds on top of it, this ecosystem lives split between 6 and 7 for a while. The very existence of compatibility packages like @typescript/typescript6 and tsc6 is an admission of that. Microsoft knows it too, which is why the announcement closes by saying it wants to "close whatever gaps remain with 7.1 and bring the community forward."
If you have a pure TS codebase, today is a good day. If you are standing on Vue or Astro, this release is not yours yet — and that is not because you did anything wrong.
References
- Announcing TypeScript 7.0 (Microsoft, 2026-07-08) — source for every figure and quote in this post
- Announcing TypeScript 7.0 RC (2026-06-18)
- Announcing TypeScript 7.0 Beta (2026-04-21)
- npm — typescript — at GA,
latestis 7.0.2,nextis in the 7.1.0-dev line - npm — @typescript/typescript6 — the 6.0 compatibility package providing the
tsc6executable - microsoft/typescript-go — the native port repository
- TypeScript 6 and the tsc-go Port — related post, from the preview era