TypeScript 컴파일러, 체커 및 LSP를 Rust로 포팅한 ts-rust (aka tsc-rs)
요약
본 기사는 LLM을 활용하여 TypeScript 컴파일러, 체커 및 LSP를 Rust로 포팅한 'ts-rust (tsc-rs)'의 개발 과정을 다룹니다. OpenAI 모델과 Claude Code를 비교하며, 특히 Opus 5.5가 시간 대비 높은 효율성을 보여주었음을 강조합니다. tsc-rs는 Go 기반 TypeScript 컴파일러를 Rust로 포팅하여 기존 `tsc`와 동일한 기능을 제공하는 초기 출시 버전입니다.
핵심 포인트
- LLM을 활용해 복잡한 컴파일러(TypeScript)를 Rust로 포팅 가능함을 입증함.
- Claude Opus 5.5가 OpenAI 모델 대비 높은 효율성과 성능을 보여줌.
- ts-rust는 Go 기반 tsc의 기능을 유지하며, `tsc`와 동일한 옵션을 사용합니다.
- 현재 Linux x64 및 macOS arm64 플랫폼에서 사용할 수 있습니다.
ts-rust (aka tsc-rs)
LLM을 사용하여 TypeScript 컴파일러, 체커 및 LSP를 Rust로 포팅할 수 있는지 확인해 보고 싶었습니다. 실제로 가능했습니다.
이 작업을 수행하는 데 토큰 비용으로 42만 달러가 넘게 들었지만, 아마도 2만 달러 정도면 충분했을 것입니다 (아래 참조).
동기(Motivations)
- 모델 역량 테스트
- 빠른 TypeScript 타입 체커 제작
- 높은 성능으로 WASM에서 작동하는 ts 체커 제작
- 밈
경고(Warnings)
이것은 초기 출시 버전입니다. 우리가 테스트한 모든 실제 프로젝트에서 100% 호환성을 가집니다. 대부분의 앱에 드롭인 대체품으로 작동해야 합니다. [알려진 문제점(Known problems)]을 참조하세요.
또한 언급할 가치가 있는 점: 저는 이 코드의 한 줄도 읽어본 적이 없습니다.
설치(Install)
경고합니다. 이것이 실제로 작동할지 전혀 모르겠습니다.
npm install -D tsc-rs
npx tsc-rs -p tsconfig.json
어떻게 진행되었나?(How did this go?)
저는 이 포팅을 완료하기 위해 많은 OpenAI 모델들을 사용했습니다. 총 GPT-5.6 Sol 및 GPT 6 Astra로 40만 달러가 넘는 API 가격 토큰을 사용했습니다. 그들은 여러 달에 걸친 /goal 루프를 통해 130만 줄 이상의 Rust 코드를 작성했지만, 84% 호환성 이상에는 도달하지 못했습니다.
Claude Code의 제한이 얼마나 적게 소모되는지 보고, Opus 5.5로 시도해 보는 것이 재미있을 것 같다고 생각했습니다. 이것은 10시간 만에 작동하는 v0를 만들었습니다.
저는 그것이 Codex 모델들이 작성한 코드를 계속 사용한다고 가정했습니다. 저는 틀렸습니다. Opus 5.5는 처음부터 시작했습니다. 시간 대비 Astra보다 더 멀리 나아갔습니다.
계속 진행하도록 내버려 두었고, 실제로 그렇게 했습니다. 총 토큰 지출은 2주 동안 API 비용으로 약 24,047달러였습니다. 저는 제 Claude 계정을 사용했고, 이는 주간 $200 플랜 제한의 925%에서 983% 사이로 계산되었습니다.
확실히 비싸지만, typescript-go에 들어간 노력의 양을 고려하면 그렇게 나쁘지는 않습니다.
"The Slop Line"
이 아래 내용은 제가 아니라 LLM들이 작성한 것입니다.
실제로 이것은 무엇인가요?(What actually is this?)
ts-rust는 Go로 작성된 Microsoft의 네이티브 TypeScript 컴파일러를 직접 포팅한 것입니다 (microsoft/TypeScript, 이전에는 typescript-go였습니다). 이는 Go의 알고리즘과 동작을 유지하며 동일한 커맨드라인(tsc), 언어 서버, API를 가집니다.
설치
npm install -D tsc-rs
npx tsc-rs -p tsconfig.json
tsc-rs는 tsc와 동일한 옵션을 사용합니다. npm 패키지 이름이 tsc-rs인 이유는 typescript 패키지와 충돌하지 않기 위함입니다. 각 릴리스에는 플랫폼별 독립형 아카이브도 제공됩니다: 옆에 라이브러리 파일이 있는 tsc 바이너리입니다.
플랫폼: Linux x64 (정적, 모든 배포판 지원) 및 macOS arm64. Windows와 Linux arm64는 아직 사용할 수 없습니다.
VS Code에서 사용하려면 npm 패키지 README를 참조하세요.
Effect 진단 (diagnostics)
tsc-rs에는 내장된 Effect 언어 서비스 진단(codes 377xxx)이 있으므로, Effect 프로젝트는 별도의 컴파일러가 필요하지 않습니다. 이들은 TypeScript 진단과 동일한 검사에서 나오며, 언어 서버에서도 표시됩니다. 이는 tsconfig에 플러그인이 있는 경우에만 실행되며, @effect/language-service와 같습니다:
{ "compilerOptions": { "plugins": [{ "name": "@effect/language-service" }] } }
규칙, 옵션 및 @effect-diagnostics 주석은 Effect-TS/tsgo 0.46.1을 포팅한 것입니다. 언어 서비스의 에디터 기능(빠른 수정, 리팩토링, 호버, 자동 완성)은 포팅되지 않았습니다.
상태
이 포트는 상위(upstream) 리비전인 microsoft/TypeScript 673a5f17d713 (2026-09-29, TypeScript 7.1.0-dev; UPSTREAM.md)에 고정되어 있으며, 해당 리비전의 Go와 비교됩니다. 비교하려면 [email protected]을 사용해야 하며, 7.0.x나 @typescript/native-preview를 사용해서는 안 됩니다. 이 빌드에서 나타나는 차이점 중 일부는 상위 동작(upstream behavior)이며, 포트가 더 새로운 고정 지점으로 이동하면 사라집니다.
- 동일한 결과. TanStack Query core와 Hono은 진단(diagnostics) 면에서 Go와 동일하게 확인됩니다. 181,711개의 포팅된 Go 테스트 모두 통과했습니다. 언어 서버 및 API 응답은 오라클 테스트 세트에서 Go와 일치합니다.
- 더 빠름. 60개 오픈 소스 프로젝트에서 타입 검사 시간이 Go 시간의 약 절반(기하 평균)이 걸립니다. 프리뷰 패키지는 PGO와 BOLT 없이 CI에서 빌드되므로 측정된 빌드보다 느립니다.
- 실제 프로젝트. 120개 오픈 소스 리포지토리에서 명령줄 출력은 아래 문제점과 Go 자체의 출력이 실행마다 변경되는 경우를 제외하고는 Go와 다릅니다.
벤치마크: T3 Code
T3 Code의 전체 타입 검사를 tsc 6, tsc 7 및 Bun의 새로운 bun check와 비교했습니다. T3 Code는 Effect를 사용하므로 두 가지 경우가 있습니다: Effect 진단이 없는 경우와 있는 경우입니다. 매번은 다섯 개의 T3 Code 프로젝트에 대한 합계 시간입니다. 숫자가 낮을수록 빠릅니다.
Effect 진단 없음
| Checker | Time | vs tsc 6 | vs tsc 7 | | :---: | :---: | :---: | :---: | :---: | :---: |
| bun check | 4.07s | 15.4× | 3.95× faster | █ |
오류 보고. tsc-rs, tsc 7 + @effect/tsgo 및 effect-tsgo diagnostics 패스는 동일한 221개의 Effect 진단 결과를 보고합니다. tsc 6은 JavaScript Effect 플러그인(@effect/language-service 0.87.4)을 사용하며, 이는 다른 것들과 다른 규칙 세트를 가지고 있습니다: 이 경우 apps/server에서 287개를 보고하는 반면, 다른 것들은 177개를 보고합니다. tsc-rs와 tsc 6은 apps/server/scripts/record-pi-rpc-replay-fixture.ts에서 TS2322 오류를 하나 더 보고합니다. TypeScript 7.1.0-dev도 이를 보고하며, pingdotgg/t3code#16704가 이를 수정했습니다.
측정 방법: 아래 실제 애플리케이션들과 동일한 머신과 방법을 사용했으며, --composite false를 추가했습니다 (apps/web은 composite입니다). T3 Code는 cd41c4ad에서, 프로젝트 apps/server, apps/web, apps/mobile, packages/client-runtime 및 packages/shared를 사용합니다. Effect가 없는 경우, 설정에는 Effect 플러그인이 없습니다. Effect가 있는 경우, tsc 7은 @effect/tsgo 0.46.1의 Effect 패치된 7.0.2이며, tsc 6은 @effect/language-service로 패치된 6.0.3입니다. 스크립트는 scripts/bench-apps/t3code.sh입니다. T3 Code의 tsc-rs 전환은 pingdotgg/t3code#16704에 있습니다.
벤치마크: 실제 애플리케이션
6개의 오픈 소스 애플리케이션에 대해 tsc 6 (JavaScript 컴파일러), tsc 7 (Go 컴파일러), tsc-rs, 그리고 bun check를 이용한 전체 타입 검사 결과를 비교했습니다. 배수는 tsc 6 대비 속도 향상률을 나타냅니다. 숫자가 낮을수록 빠릅니다.
| App | Lines checked | tsc 6 | tsc 7 | tsc-rs | bun check |
|---|---|---|---|---|---|
| VS Code | 3.75M | 54.56s | 6.84s (8.0×) | 4.20s (13.0×) | 1.62s (33.7×) |
| ... |
tsc 7 대비, tsc-rs는 1.61배 빠르고 bun check는 2.95배 빠릅니다 (기하 평균). tRPC를 제외한 모든 애플리케이션에서 bun check가 가장 빠릅니다.
bun check는 다른 어떤 체커도 보고하지 못한 오류(Sentry에서 3개, tRPC에서 2개)를 보고합니다.
각 설정은 tsc 7.0.2로 0개의 오류를 검사했습니다. 다른 차이점들은 다음과 같습니다:
tsc-rs는 VS Code에서 10개, Sentry에서 2개의 오류를 보고합니다. TypeScript 7.1.0-dev (typescript@next)도 동일한 줄 단위의 오류를 보고합니다.tsc-rs는 7.1 개발 버전을 포팅했는데, 이 버전에는 7.0.2에 없는 검사 기능이 포함되어 있습니다.tsc6은 VS Code에서 9개의 오류를 보고합니다.
측정 방법: Apple M4 Pro (12 코어, 48 GB), macOS 26.5.1. hyperfine를 사용했으며, 워밍업 실행 1회 후 5번의 중앙값(median)을 측정했습니다. --noEmit --incremental false 옵션을 사용했습니다. 각 체커는 기본 스레드 수를 사용합니다. tsc 7과 tsc-rs는 npm 런처 없이 네이티브 바이너리로 실행됩니다. tsc 6은 VS Code와 Sentry에서 기본 힙 메모리를 초과하여 발생했기 때문에, Node 24.19 및 16 GB의 힙을 사용하여 실행되었습니다. 버전: tsc-rs 0.1.0, TypeScript 7.0.2 및 6.0.3, Bun canary bd599f5af. Lines checked는 .d.ts 파일을 포함한 tsc 7 --extendedDiagnostics 카운트입니다. 위의 T3 Code 벤치마크도 동일한 장비와 방법을 사용했습니다.
네 개의 애플리케이션은 tsc 7로 0개의 오류를 검사하기 위해 변경이 필요했지만, 그 외에는 아무것도 변경되지 않았습니다.
- Excalidraw: TS 7에서 제거했기 때문에
baseUrl이 필요하지 않습니다. - TypeORM: TS 7에서
node를 제거했기 때문에moduleResolution이node에서nodenext로 변경되었습니다. - VS Code: postinstall이 추가하는
electron타입 정의입니다. - Playwright: 빌드가 생성하는 소스 파일들입니다.
테이블에 포함되지 않은 두 개의 앱은 다음과 같습니다:
- rxjs main은 워크스페이스 패키지들이 먼저 빌드되어야 합니다.
- date-fns는 프로젝트 참조를 사용합니다. 여기서는
tsc -p와bun check가 서로 다른 작업을 수행합니다.
스크립트는 scripts/bench-apps에 있습니다: setup.sh <디렉토리>를 실행한 다음, run.sh <디렉토리> 및 summary.py <디렉토리>, 그리고 T3 Code의 경우 t3code.sh <디렉토리>를 사용합니다.
알려진 문제점 (Known problems)
- 일부 모노레포(monorepos)에서는 워크스페이스 패키지의 소스 파일이
node_modules와 직접 가져오기(direct import)를 통해 모두 접근 가능합니다. 이 경우,tsc-rs는tsc보다 더 많은 파일을 출력할 수 있으며, 해당 파일들에 대해 TS6059 (파일이rootDir아래에 있지 않음) 오류를 보고합니다.tsc는 타이밍을 기준으로 이를 결정하므로 실행마다 결과가 달라집니다. 반면,tsc-rs는 모든 실행에서 동일한 결과를 제공합니다 (TypeScript 6의 결과). tsc -b사용 시, 한 프로젝트가 프로젝트 참조 없이 다른 프로젝트의 출력을 가져올 때,tsc-rs는 몇 가지 경우(예:noEmitOnError프로젝트, 비증분(non-incremental)noCheck프로젝트, 기본 빌더로만 출력해야 하는 여러 대규모 프로젝트, 또는 읽기 프로젝트가 작성자보다 먼저 빌드되는 다른 프로젝트를 참조하는 경우)에tsc가 새 출력을 읽는 반면, 이전 또는 누락된 출력을 여전히 읽을 수 있습니다. 이를 수정하려면 참조(reference)를 추가하세요.- 에디터에서 장시간 편집 세션 동안 메모리가 서서히 증가합니다 (편집 1,000개당 약 20 MiB).
tsc보다 초기에는 12~24% 높지만, 측정된 세션 중 편집 20회 이후부터는tsc보다 낮은 수준을 유지했습니다 (최대 편집 2,190회). tsc-rs --version은 포팅한 TypeScript 버전(7.1.0-dev)을 출력하며, npm 버전을 출력하지 않습니다. 컴파일러는 이 버전과typesVersions를 일치시킵니다.
개발 (Development)
crates/ts_goport가 컴파일러입니다. 이에는 두 개의 크레이트(crate)인 goport_util과 goport_lsproto가 crates/ts_goport/parts에 있으며, crates/ts_goport/libs의 라이브러리 파일들을 사용합니다. tools/ts_ast_codegen은 crates/ts_goport/src/astdata를 생성하고, tools/ts_diagnostics_codegen은 crates/ts_goport/src/diagnostics/catalog.rs와 crates/ts_goport/src/diag.rs를 생성합니다. crates/ts_wasm은 WebAssembly 빌드(npm/wasm)입니다.
./scripts/run-cargo-capped.sh build --release -p ts_goport --bins
./scripts/verify.sh
생성되는 바이너리(bin)는 goport(타입 검사기, type check)와 tsgo (Go의 tsgo 명령줄 도구)입니다. Go 기반 테스트(baseline tests)는 다음으로 실행됩니다:
TS_GO_REPO=/path/to/typescript-go ./scripts/run-cargo-capped.sh test -p ts_goport --test go_baselines.
- 포팅 규칙: crates/ts_goport/PORTING.md
- 측정 및 게이트 스크립트: scripts/goport
- npm 패키지 및 릴리스: npm/README.md
- 타입 검사기 작업 규칙: AGENTS.md, 책임성 규칙 및 저장된 상태
- 프로젝트 시작 방법: docs/history.md
릴리스 (Releases)
v<버전>과 같은 태그를 푸시합니다(예: v0.1.0). 릴리스 워크플로우는 패키지를 빌드하고, 패킹하며, 테스트한 후, npm에 게시하고 GitHub 릴리스를 생성합니다. 안정 버전은 latest 디스트 태그로, 프리릴리스 버전(v0.2.0-beta.1)은 next와 GitHub 프리릴리스로 배포됩니다. npm/README.md를 참조하세요.
라이선스 (License)
AI 자동 생성 콘텐츠
본 콘텐츠는 HN AI Posts의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기