라떼군 이야기


TypeScript 7, Go로 다시 만든 컴파일러는 무엇을 바꿨나

TypeScript는 오랫동안 자기 자신으로 만들어졌다. 컴파일러 tsc와 언어 서비스가 TypeScript로 작성되고, JavaScript로 컴파일된 뒤 Node.js 위에서 실행됐다. 구조는 우아했지만 한계도 분명했다. 코드가 수백만 줄에 이르면 타입 검사와 에디터 초기화에 적지 않은 시간이 걸렸다.

Microsoft는 TypeScript 7에서 이 기반을 바꿨다. 기존 구현의 구조와 동작을 최대한 유지하면서 컴파일러와 언어 서비스를 Go로 옮겼다. 새 구현은 네이티브 코드와 공유 메모리 기반의 병렬 처리를 활용한다. 그 결과 전체 빌드는 보통 8~12배 빨라졌다.

TypeScript 7은 2026년 4월 베타, 6월 RC를 거쳐 7월 8일 정식 출시됐다. 이제 별도의 프리뷰 패키지가 아니라 평소처럼 설치하면 된다.

npm install -D typescript
npx tsc

왜 Rust가 아니라 Go였나

포팅 계획이 공개되자 “성능이 목적이라면 Rust가 더 알맞지 않느냐"는 질문이 나왔다. TypeScript 팀이 Go를 선택한 이유는 단순한 실행 속도가 아니었다. 기존 컴파일러의 구조를 되도록 그대로 옮기면서 두 구현의 동작을 일치시키기 쉬운 언어가 필요했다.

TypeScript 컴파일러는 함수 중심으로 짜여 있다. AST와 심벌 테이블은 서로를 참조하는 복잡한 그래프를 이루며, 객체의 수명도 단순하지 않다. 이런 구조를 Rust로 옮기려면 소유권과 수명 관리에 맞춰 상당 부분을 다시 설계해야 할 가능성이 컸다.

반면 Go는 가비지 컬렉션을 제공한다. 순환 참조가 있는 자료구조를 비교적 자연스럽게 표현할 수 있고, 기존 TypeScript 코드를 구조적으로 비슷하게 옮기기에도 유리하다. 여러 플랫폼용 네이티브 바이너리를 만들기 쉽고 동시성 지원도 잘 갖춰져 있다.

중요한 점은 이번 작업이 새로운 컴파일러를 처음부터 설계한 ‘재작성’이 아니라는 것이다. TypeScript 팀은 기존 코드의 구조와 타입 검사 논리를 최대한 충실하게 포팅했다. 목표는 더 나은 언어 규칙을 만드는 것이 아니라, 같은 입력에 같은 결과를 내면서 훨씬 빠르게 실행하는 것이었다. TypeScript 7.0 RC 발표문, Why Go? 논의

실제로 얼마나 빨라졌나

정식 버전 발표에 실린 측정 결과를 보면 성능 차이가 분명하다.

프로젝트TypeScript 6TypeScript 7향상 폭
VS Code125.7초10.6초11.9배
Sentry139.8초15.7초8.9배
Bluesky24.3초2.8초8.7배
Playwright12.8초1.47초8.7배
tldraw11.2초1.46초7.7배

프리뷰 단계의 초기 측정에서도 비슷한 결과가 나왔다. 약 150만 줄 규모의 VS Code는 77.8초에서 7.5초로, Playwright는 11.1초에서 1.1초로 줄었다. TypeORM은 17.5초에서 1.3초로 빨라졌다.

속도 향상은 두 가지 변화에서 나온다. 먼저 JavaScript 대신 네이티브 기계어로 실행된다. 여기에 파싱과 타입 검사, 코드 출력 등을 여러 스레드에서 병렬로 처리한다.

기본 타입 체커 수는 4개다. 코어가 많은 환경에서는 --checkers 값을 늘려 더 빠른 결과를 얻을 수 있다. 공식 측정에서 --checkers 8을 사용했을 때 VS Code 빌드는 7.51초까지 줄었다. 다만 체커를 늘리면 메모리 사용량도 커진다. CI처럼 자원이 제한된 환경에서는 오히려 수를 줄이는 편이 나을 수 있다.

메모리 사용량도 줄었지만 “절반 수준"이라고 일반화하기는 어렵다. 정식 버전 자료에서는 프로젝트에 따라 약 6~26% 감소했다. 메모리와 속도는 코드 구조와 병렬 처리 설정에 따라 달라지므로, 실제 저장소에서 직접 측정하는 것이 안전하다. TypeScript 7.0 정식 발표, 초기 네이티브 포트 성능 측정

에디터에서도 빨라진다

이번 변화는 tsc에만 그치지 않는다. 에디터가 사용하는 언어 서버도 Go 기반으로 바뀌었다.

새 서버는 TypeScript 전용 프로토콜 대신 표준 LSP(Language Server Protocol)를 사용한다. 여러 요청을 동시에 처리할 수 있으며 자동 임포트, 호버 정보, 인레이 힌트, 코드 렌즈, 정의로 이동, 시맨틱 하이라이팅, 임포트 정렬 같은 기능을 제공한다.

초기 측정에서 VS Code 프로젝트를 불러오는 시간은 9.6초에서 1.2초로 줄었다. 정식 버전을 실제 업무에 적용한 Canva는 에디터에서 첫 오류가 나타나기까지 걸리는 시간이 약 58초에서 4.8초로 줄었다고 밝혔다. Slack은 CI 타입 검사 시간을 약 7분 30초에서 1분 15초로 단축했다.

LSP 채택은 VS Code 밖에서도 의미가 있다. 에디터가 기존 tsserver 전용 프로토콜을 따로 구현하지 않아도 표준 방식으로 TypeScript 언어 서버와 통신할 수 있기 때문이다. 다만 에디터마다 연동 상태와 지원 기능에는 차이가 있을 수 있으므로 해당 에디터의 문서를 확인해야 한다.

마이그레이션에서 확인할 부분

TypeScript 7은 TypeScript 6의 타입 검사 규칙과 명령행 동작을 최대한 유지한다. 따라서 먼저 6으로 올려 폐기 경고와 설정 변경을 정리한 다음 7로 넘어가는 경로가 가장 안전하다.

특히 TypeScript 7에서는 TypeScript 6에서 폐기된 설정이 오류로 바뀐다. target: es5, moduleResolution: node, moduleResolution: classic, baseUrl, module: amd 같은 설정은 더 이상 지원되지 않는다. strict가 기본으로 활성화되고 types의 기본값이 빈 배열로 바뀌는 등 기본 설정에도 변화가 있다. 기존 프로젝트라면 tsconfig.json을 먼저 점검해야 한다.

더 큰 제약은 프로그래밍 API다. TypeScript 7.0은 안정적인 컴파일러 API를 제공하지 않는다. typescript-eslint, 커스텀 트랜스포머, 일부 웹팩 로더처럼 typescript 모듈을 직접 불러오는 도구는 당분간 TypeScript 6 API가 필요하다. 이를 위해 Microsoft는 @typescript/typescript6 호환 패키지를 제공한다.

Vue, Svelte, Astro, MDX처럼 TypeScript 언어 서비스를 내부에 포함하는 도구와 Angular의 템플릿 타입 검사는 아직 TypeScript 7을 온전히 활용하기 어렵다. 이런 프로젝트에서는 CLI 타입 검사에 TypeScript 7을 쓰고, 에디터나 관련 도구에는 TypeScript 6을 병행하는 구성이 필요할 수 있다. 새 프로그래밍 API는 TypeScript 7.1에서 제공될 예정이다.

결론

TypeScript 7의 핵심은 새로운 문법이 아니다. 같은 타입 검사를 훨씬 짧은 시간에 끝내는 실행 기반의 교체다.

일반적인 애플리케이션은 typescript 패키지를 올리는 것만으로 성능 향상을 얻을 가능성이 크다. 반면 컴파일러 API나 언어 서비스 플러그인에 의존하는 도구는 아직 TypeScript 6을 함께 써야 할 수 있다.

따라서 마이그레이션 순서는 단순하다. 먼저 TypeScript 6에서 폐기된 설정과 동작을 정리한다. 그다음 TypeScript 7의 tsc를 CI와 로컬 환경에 적용해 속도와 메모리를 측정한다. 마지막으로 ESLint, 프레임워크 플러그인, 커스텀 트랜스포머처럼 컴파일러 내부에 연결된 도구의 호환성을 따로 확인하면 된다.

내 저장소에서 재보기 전에는 모른다

위의 배수는 모두 남의 저장소에서 나온 값이다. 본문에도 적었듯, 속도와 메모리는 코드 구조와 병렬 처리 설정에 따라 갈린다. 노트북 한 대로 확인할 수 있는 것부터 해보면 된다.

내 저장소의 배수를 직접 재본다. typescript 패키지를 올리고 npx tsc를 돌린 뒤, 올리기 전 시간과 나란히 적어 둔다. 여기에 --checkers를 2, 4, 8로 바꿔 가며 빌드 시간과 최대 메모리를 같은 표에 채우면 된다. 기본값은 4이고 공식 측정에서는 8에서 가장 좋은 숫자가 나왔지만, 체커를 늘리면 메모리도 함께 늘어난다. 따라서 CI 컨테이너에 메모리 상한이 있으면 답이 달라진다. 과제 저장소처럼 작은 코드베이스에서는 배수가 거의 나오지 않을 수도 있다. 그것도 알아둘 만한 결과다.

폐기 설정 스캐너를 만든다. tsconfig.json을 읽어 target: es5, moduleResolution: node, moduleResolution: classic, baseUrl, module: amd가 있는지 표시하는 짧은 스크립트다. 확장 설정까지 따라가 합쳐진 결과를 봐야 정확하다는 점이 생각보다 까다롭다. 여러 저장소를 한꺼번에 훑으면 마이그레이션 순서를 정할 자료가 그대로 나온다.

typescript를 직접 불러오는 의존성을 목록으로 뽑는다. 프로그래밍 API가 없다는 제약이 실제로 걸리는 지점이 여기다. 의존성 가운데 typescript를 peer나 직접 의존으로 둔 것을 골라내면, 그 목록이 곧 TypeScript 6을 당분간 함께 둬야 하는 이유가 된다. 짐작만으로 미루기보다 목록으로 확인하는 편이 빠르다.

하나만 고른다면 세 번째다. 배수가 저장소마다 다르다는 이야기는 이미 여러 번 나왔지만, 컴파일러 API 때문에 발이 묶이는 도구 목록은 팀마다 다르다. 그 목록을 모아 놓은 자료는 아직 못 봤다. 재본 숫자나 뽑아 본 목록이 있으면 알려 주시라. 여러 저장소의 숫자와 목록이 모이면 그것만으로 한 편이 된다.

참고

제품 기획·개발 파트너 찾으시나요? 개인·팀·기업 모두 환영. 문제 정의부터 출시까지 함께합니다.

Copyright © 2026 - present Mr. Latte. All Rights Reserved.

hello@mrlatte.net

v2026.08.25.0628