TypeScript 7 공식 출시, 진짜 압도적으로 빠릅니다

BBetter Stack
Computing/SoftwareInternet Technology

Transcript

00:00:00TypeScript 7이 공식 출시되었습니다. 1년이 넘는 고된 개발 끝에
00:00:05컴파일러를 Go로 이식하는 과정에서 AI만으로도 전체를 구현할 수 있음이 증명되었죠.
00:00:10개발자들도 아주 기뻐할 겁니다. 이제 `npm install typescript`를 실행하면
00:00:16Go 컴파일러가 포함된 버전 7을 받게 됩니다. 며칠 전 마이크로소프트의
00:00:20발표 영상에 이어, 어떻게 이런 엄청난 성능 향상을
00:00:25이뤄냈는지 파헤쳐 보려 합니다. 결과는 정말 놀랍습니다. 새 컴파일러는
00:00:318천 개 가량의 파일, 130만 줄에 달하는 VS Code 코드베이스를 기존 컴파일러의 125초 대신
00:00:39단 10초 만에 빌드해 냅니다. TypeScript가 GitHub 인기 언어 1위를
00:00:44당당히 차지하고 있는 상황에서, 새 컴파일러는 무수한 삶을 바꿔놓을 것입니다. 생각만 해도 벅차오르네요.
00:00:49버전 6과 7 사이의 거의 동일한 기능들을 훑어보기보다는,
00:00:54어떻게 이런 성능 개선을 달성했는지 명확히 짚어보겠습니다. 새 컴파일러를 살펴보고
00:00:59무엇이 이토록 빠르게 만드는지 살펴보겠습니다. 왜 재작성했을까요? C#의 창시자이자 마이크로소프트 테크니컬 펠로우인
00:01:09C#의 창시자이자 MS 테크니컬 펠로우인 아놀드 하일스버그는 아주 솔직하게 말했습니다. JavaScript는 UI와 브라우저에 최적화되어 있지,
00:01:16연산 집약적인 워크플로나 컴파일러에는 그다지 최적화되어 있지 않다고요. 이유야 명확합니다. 싱글
00:01:22스레드 방식이라 추상 구문 트리(AST)나 타입 검사를 처리할 때 단일 코어 접근 방식으로는
00:01:27확장성에 한계가 있기 때문이죠. 기술적으로 워커(Worker)에 작업을 분산할 수도 있지만
00:01:32데이터의 직렬화/직렬화 해제가 필요해 속도가 느려지고 메모리 부담이 커집니다. 게다가
00:01:38이 모든 것을 관리하는 복잡성도 다뤄야 하죠. 그래서 목적에 딱 들어맞는
00:01:43언어인 Go를 선택해 획기적인 성능 향상을 이뤄냈습니다. Go는 컴파일 언어라
00:01:48해석 단계를 거치지 않고 CPU에서 컴파일된 코드를 직접 실행하며,
00:01:54공유 메모리 기반으로 여러 실행 스레드를 동시에 손쉽게 돌릴 수 있는 훌륭한 동시성 모델을 갖추고 있습니다.
00:02:00덕분에 단 하나의 코어가 아닌 컴퓨터의 모든 코어를 활용할 수 있게 되었죠.
00:02:06속도 향상의 원인은 대략 반반입니다. 절반은 네이티브 코드로 작동하는 데서 올리고,
00:02:12나머지는 공유 메모리 동시성에서 옵니다. Go는 이 작업에 있어 최적의 언어입니다.
00:02:17단순히 Go가 더 빠른 것을 넘어, 문제 해결에 투입할 자원 자체가 늘어난 셈이죠. 결과가
00:02:23이를 증명해 줍니다. 수치를 보면 130만 줄의 VS Code 코드는 구형 컴파일러에서 125.7초가 걸렸지만
00:02:3210.6초 만에 끝나 11.9배 향상되었고, BlueSky 프로젝트는 24.3초에서 2.8초로 8.7배 향상되었습니다.
00:02:42Playwright는 12.8초에서 1.5초로 줄어 8.7배 빨라졌죠. 재미있게도 Better Stack 구독에는
00:02:49단 1초밖에 안 걸립니다. 앞으로 격차는 더 벌어질 것입니다. 단일 코어 속도는
00:02:54예전만큼 빨라지지 않지만, 코어 수는 늘어나고 있으니까요. 예로 제가 사용하는 M3 Max에는
00:03:0014개나 되는 코어가 있습니다. 대학 시절 쿼드코어 Intel i7으로
00:03:06괴물 같은 조립 PC를 맞췄던 기억이 나네요. 기존 JavaScript 컴파일러는 그 코어 중 딱 하나만 썼지만,
00:03:11Go를 이용하면 모든 코어의 잠재력을 이끌어냅니다. 코어가 많을수록
00:03:17더 뛰어난 성능을 얻게 되죠. 이 기기에서 대형 프로젝트를 버전 6으로 컴파일하면 45초가
00:03:24걸리는 데 반해, 버전 7에서는 3초대까지 단축할 수 있습니다.
00:03:29컴파일 과정에는 여러 단계가 있고 타입 검사는 그중 하나일 뿐입니다. Go는
00:03:344개의 타입 체커를 띄워 각각 코드베이스의 4분의 1씩 검사하도록 만듭니다. 하지만
00:03:39속도를 더 끌어올릴 수 있죠. 컴파일 시 체커 옵션을 12로 설정하면 더욱 빠른 성능을 얻을 수 있습니다.
00:03:45TypeScript 7과 6의 차이를 보기 위해 내 기기에 VS Code 저장소를 받았습니다.
00:03:51기본적으로 제 기기의 `tsc`는 이제 TypeScript 7을 가리킵니다. 진단 명령을
00:03:57실행해 보면 5.4초가 걸렸고, 대부분의 시간은 타입 검사(Check time)에
00:04:02소요되었습니다. (4.7초) 이것 역시 더 단축할 수 있습니다.
00:04:08`--checkers 12` 플래그를 더해주면 전체 시간이 5.4초에서 3.5초로 줄어듭니다.
00:04:15이 과정에서 검사 시간이 깎여나간 거죠. 4.7초였던 검사 시간이 2.9초까지 떨어졌습니다. 이제 동일한
00:04:20명령을 실행하되 이번에는 TypeScript 6을 써보겠습니다. 시간이 좀
00:04:23걸릴 테니 빠르게 넘어가죠. 잠시 기다린 결과, TypeScript 6은
00:04:28모든 코어를 다 활용해 3.5초 만에 끝낸 버전 7에 비해 45.3초나 걸렸습니다.
00:04:36내 M3 Max 칩 기준 무려 15배나 향상된 셈입니다. 3.5초라는 수치는
00:04:43여기서 나온 것이죠. 물론 이렇게 하면 다른 프로세스의 자원을 훔쳐 오겠지만,
00:04:47아무것도 안 하고 있다면 시스템 자원을 100% 활용하는 편이 낫습니다. 이제 새 컴파일러의 실제 코드를
00:04:52살펴보며 Go가 어떻게 이런 성능을 냈는지 알아보죠. 여기 파일 내의 모든 선언을 수집하고
00:04:57어느 스코프에 속하는지 파악하는 `bindSourceFiles` 함수가 있습니다.
00:05:03수천 개에 달할 수도 있는 파일을 다룰 때, 각 파일을 순회하면서 바인딩 작업을 큐에 넣고
00:05:09모두 완료되기를 기다립니다. 가장 놀라운 점은 여러 코어로 작업이 어떻게
00:05:14분산될지 신경 쓸 필요가 없다는 것입니다. Go의 런타임이 알아서 처리해 주죠. 스레드를 생성하거나
00:05:20코어 간의 복잡한 통신을 관리할 필요 없이, 단지 할 일을 전달하기만 하면 알아서 처리 방식을 찾아냅니다.
00:05:26JavaScript에서도 거의 똑같은 코드를 작성할 수 있지만, CPU 바운드 작업에서는 무의미합니다.
00:05:32Promise가 병렬 처리되는 것처럼 착각하게 만들어도 여전히 단일 스레드에서 순차 실행될 뿐입니다.
00:05:38워커(Worker)를 쓰는 대안도 있지만 객체를 직접 공유할 수 없고 SharedArrayBuffer를 통한 바이트 단위 공유만 가능합니다.
00:05:43따라서 파싱된 구문 트리를 워커로 전달하려면 전체를 직렬화해서 복사한 다음
00:05:48반대편에서 다시 재구성해야 합니다. 대용량 파일에서는 그 비용이 본 작업보다 클 수 있습니다.
00:05:53기본적으로 이러한 점들 때문에 Go가 CPU 바운드 작업에 구조적으로 훨씬 우수합니다.
00:05:58모든 동시성을 대신 처리해 주는 런타임이 있고, 공유 메모리가 있어 객체를
00:06:03복사할 필요 없이 곧바로 전달할 수 있죠. 컴파일 시간 외에 체감되는
00:06:07가장 큰 부분은 언어 서버(LSP)의 속도일 것입니다. 대규모 TypeScript 코드베이스에서 작업해 본 사람이라면
00:06:13타입 검사가 끝날 때까지 기다리는 고통을 다 알죠. Intel Mac을 쓸 때는 그 고통이 뼈에 사무쳤습니다. 몇 년 전
00:06:20프로젝트를 진행할 때 저장소를 열면 빨간 물결선이 나타나기까지
00:06:24최대 2분까지 멍하니 기다려야 했습니다. 코드를 조금 수정할 때마다
00:06:29엄청나게 둔해졌죠. 개발자 경험은 최악이었고, 누구도 그 코드베이스를 건드리고 싶지 않아 했습니다.
00:06:34반면 새 언어 서버를 사용하면 IDE에서 즉각적인 피드백을 받게 됩니다.
00:06:40파일을 열어 수정하면 밀리초 단위 만에 곧바로 에러 표시를 확인할 수 있죠. 설령
00:06:46엄청나게 거대한 코드베이스에서 작업하더라도 말이죠. 성능 외에도 새 언어 서버는 더욱 안정적입니다.
00:06:51타입 검사가 멈춰 버려서 IDE를 재시작해야 했던 일이 대폭 줄어들었습니다. TypeScript 7은
00:06:57언어 서버 명령 실패율을 80% 이상 낮췄고, 서버 크래시는 60% 이상 줄였습니다.
00:07:04벽에 노트북을 던지는 일이 줄었으니 환경 보호에도 꽤 이로울 겁니다.
00:07:08MS가 지구 환경까지 생각할 줄은 몰랐네요. 이번 업데이트는 완전 재작성이 아닌
00:07:13'이식'이라는 점도 짚고 넘어갈 만합니다. TypeScript 팀은 새 컴파일러가 기존 버전과
00:07:19완벽히 호환되도록 세심히 공을 들였습니다. 속도를 제외하면 차이점조차 느끼지 못할 겁니다.
00:07:24하지만 본인 프로젝트에서 바로 TypeScript 7을 돌려볼 수 있어도, 자주 쓰는
00:07:29패키지들의 호환 업데이트를 기다려야 할 수 있습니다. 프로그래밍 방식 API가 아직 제외된 상태라,
00:07:35해당 API에 의존하는 typescript-eslint, ts-jest, ts-node 같은
00:07:42패키지들은 7.1 버전이 나올 때까지 다소 지연될 것입니다. 현재 정식 버전 TypeScript 7을 받으실 수 있지만,
00:07:47VS Code용 TypeScript 7 확장 프로그램은 직접 설치하셔야 합니다. 기본 패키지도 추후
00:07:53업데이트되겠지만, 지금은 마켓플레이스에서 'TypeScript 7' 확장을 설치하기만 하면
00:07:58모든 것이 정상적으로 작동합니다. TypeScript 7의 상세 기능들을 확인하고 싶다면
00:08:03해당 내용을 정리해둔 관련 영상 링크를 확인해 보세요. 이번 분석 영상이 마음에 드셨다면
00:08:08Better Stack을 구독해 주세요. 유용한 정보가 되었길 바라며, 이제
00:08:12TypeScript 7이 가져다줄 압도적인 개발 속도를 직접 경험해 보세요. 저도 아주 즐겁게
00:08:16사용하게 될 것 같네요. 시청해 주셔서 감사드리며, 다음 영상에서 다시 찾아뵙겠습니다.

Key Takeaway

TypeScript 7은 컴파일러를 Go 언어로 재작성하여 모든 CPU 코어를 활용하는 공유 메모리 동시성을 구현함으로써 VS Code 기준 컴파일 속도를 125.7초에서 10초 대까지 최대 15배 단축했다.

Highlights

  • TypeScript 7은 컴파일러를 Go 언어로 이식하여 기존 대비 획기적인 컴파일 속도 향상을 달성했다.

  • VS Code 코드베이스(130만 줄, 8천 개 파일) 컴파일 시간이 기존 125.7초에서 10.6초로 11.9배 단축되었다.

  • 네이티브 코드 실행 성능과 Go의 공유 메모리 기반 동시성 처리가 속도 향상의 핵심 원인이다.

  • 타입 검사 시 `--checkers 12` 플래그를 추가하면 멀티코어를 활용해 검사 시간을 4.7초에서 2.9초로 줄일 수 있다.

  • 프로그래밍 방식 API가 필요한 typescript-eslint, ts-jest 등 일부 패키지는 7.1 버전 출시 전까지 호환이 지연된다.

Timeline

TypeScript 7 공식 출시 및 주요 성능 지표

  • TypeScript 7이 공식 출시되었으며 `npm install typescript` 명령어로 즉시 사용할 수 있다.
  • 컴파일러 엔진이 Go 언어로 이식되면서 컴파일 속도가 비약적으로 개선되었다.
  • VS Code 코드베이스 기준 빌드 시간이 125초에서 10초로 줄어들었다.

1년 이상의 개발 기간을 거쳐 Go 언어로 이식된 TypeScript 7이 정식 출시되었다. 130만 줄, 8천여 개 파일 규모의 VS Code 프로젝트를 기존 125.7초에서 10.6초 만에 컴파일한다. 별도의 복잡한 절차 없이 npm 패키지 설치만으로 Go 컴파일러 기반의 새 버전을 적용할 수 있다.

Go 이식 선택 이유와 동시성 아키텍처

  • JavaScript의 싱글 스레드 한계가 연산 집약적인 컴파일 작업의 병목으로 작용했다.
  • Go 언어의 네이티브 컴파일 실행과 공유 메모리 동시성 모델이 멀티코어 활용을 가능하게 했다.
  • 성능 향상 요소의 절반은 네이티브 실행, 나머지 절반은 공유 메모리 동시성에서 발생한다.

기존 JavaScript 기반 컴파일러는 싱글 스레드 특성상 단일 CPU 코어만 사용했다. 워커(Worker) 프로세스를 쓰는 방식은 AST 및 데이터 직렬화/직렬화 해제 비용 때문에 메모리 부담과 속도 저하를 초래했다. Go 언어로 전환함으로써 데이터를 복사하지 않고 공유 메모리를 통해 여러 스레드가 동시에 작업을 처리하도록 구조를 개선했다.

실제 프로젝트 컴파일 벤치마크 테스트

  • BlueSky 프로젝트는 24.3초에서 2.8초로, Playwright는 12.8초에서 1.5초로 컴파일 시간이 단축되었다.
  • M3 Max 14코어 환경에서 `--checkers 12` 옵션을 적용 시 VS Code 컴파일 시간이 3.5초까지 줄어든다.
  • 동일 환경에서 TypeScript 6은 45.3초가 걸려 버전 7이 약 15배 빠른 성능을 보였다.

컴퓨터의 코어 수가 증가함에 따라 멀티코어를 지원하는 TypeScript 7의 성능 격차는 더 벌어진다. M3 Max 칩셋 환경에서 진단 명령 실행 시 타입 검사 단계에 대부분의 시간이 소요된다. 병렬 체커 수량을 12개로 늘리는 옵션을 주면 타입 검사 시간이 4.7초에서 2.9초로 감소하여 전체 3.5초 만에 작업이 완료된다.

Go 런타임의 병렬 작업 처리 메커니즘

  • Go 런타임이 코어 간 작업 분산과 스레드 관리를 자동으로 처리한다.
  • JavaScript의 Promise나 Worker 기반 병렬처리와 달리 객체 복사 비용이 발생하지 않는다.
  • 대용량 파일 바인딩 작업 시 CPU 바운드 처리 효율이 극대화된다.

`bindSourceFiles` 함수처럼 수천 개 파일의 선언을 수집하는 작업 시 Go 런타임은 작업 큐를 알아서 여러 코어로 분산한다. JavaScript에서는 SharedArrayBuffer 바이트 단위 공유 외에는 객체를 스레드 간 직접 전달할 수 없어 직렬화 비용이 발생하지만, Go는 공유 메모리 구조 덕분에 객체를 즉시 스레드 간에 넘겨줄 수 있다.

언어 서버(LSP) 안정성 및 생태계 패키지 호환성

  • 언어 서버 오류 발생률이 80% 이상 감소하고 서버 크래시 비율이 60% 이상 줄어들었다.
  • IDE 내 진단 피드백 반응 시간이 밀리초 단위로 단축되었다.
  • 프로그래밍 방식 API 미지원으로 일부 패키지(typescript-eslint, ts-jest 등)는 7.1 버전까지 업데이트가 지연된다.

대규모 코드베이스에서 코드 수정 시 즉각적인 에러 하이라이팅이 제공된다. 기존 버전 대비 호환성을 완벽히 유지하도록 설계되었으나, 내부 프로그래밍 방식 API는 아직 구현되지 않은 상태다. 이에 의존하는 typescript-eslint, ts-jest, ts-node 등의 도구는 TypeScript 7.1 출시 시점까지 완전히 호환되지 않을 수 있으며, VS Code 환경에서는 마켓플레이스의 TypeScript 7 확장 프로그램을 직접 설치해 사용할 수 있다.

Community Posts

View all posts