Tsonic — TypeScript를 네이티브 바이너리로 컴파일하는 실험
TypeScript → C# → NativeAOT 파이프라인으로 네이티브 실행 파일을 만드는 Tsonic. 어떻게 동작하고, 어떤 한계가 있는지 살펴봤다.
TypeScript를 네이티브로 실행하고 싶다면
TypeScript는 JavaScript로 트랜스파일된 뒤 런타임에서 실행된다. 이 구조는 편리하지만 네이티브 바이너리의 성능이나 배포 단순성을 원하는 경우엔 부족하다. Bun처럼 더 빠른 런타임으로 갈 수도 있지만, 아예 네이티브 코드로 컴파일하는 건 다른 이야기다.
Tsonic은 그 경로를 실험하는 프로젝트다. TypeScript 코드를 C#으로 변환하고, 다시 .NET NativeAOT로 네이티브 바이너리 또는 라이브러리를 만든다.
파이프라인 구조
TypeScript 소스
↓
Tsonic 컴파일러 (AST 파싱)
↓
C# 코드 생성
↓
.NET NativeAOT 컴파일
↓
네이티브 바이너리 / .NET 어셈블리
비유하면 영어 소설을 독일어로 번역한 뒤, 독일어 출판사 인쇄기로 책을 찍어내는 것이다. 원본 언어(TypeScript)를 직접 인쇄하는 게 아니라, 중간 번역(C#)을 거쳐 최종 결과물을 만든다.
[💡 잠깐! 이 용어는?] NativeAOT (Native Ahead-of-Time Compilation): .NET 런타임 없이 실행 가능한 네이티브 바이너리를 만드는 .NET 기술. JIT 컴파일 없이 미리 기계어로 변환되기 때문에 콜드 스타트가 빠르고 배포가 단순하다.
기본 사용법
# 프로젝트 초기화 (기본 CLR 환경)
tsonic init
# JavaScript 스타일 API 사용
tsonic init --surface @tsonic/js
# Node.js 모듈 지원
tsonic init --surface @tsonic/nodejs// @tsonic/js surface를 사용하는 경우
import { console } from '@tsonic/js'
const name: string = 'world'
console.log(`Hello, ${name}!`)
// nameof() 등 Tsonic 고유 intrinsics
const propName = nameof<User>('firstName') // "firstName"[💡 잠깐! 이 용어는?]
Surface (Tsonic): Tsonic에서 런타임 환경의 성격을 결정하는 설정. CLR, @tsonic/js, @tsonic/nodejs 중 선택하며, 어떤 내장 API가 TypeScript 코드에서 접근 가능한지를 정의한다.
지원하는 TypeScript 기능
V1 기준 Tsonic이 처리하는 주요 기능들:
| 기능 | 지원 여부 | 비고 |
|---|---|---|
| 기본 타입, 인터페이스 | ✅ | |
Promise .then/.catch/.finally | ✅ | lowering 방식 |
| Object literal (accessor, computed key) | ✅ | |
nameof<T>(), sizeof<T>() | ✅ | 언어 intrinsic |
Dynamic import() | ✅ | closed-world 방식 |
| npm 의존성 (일반 JS) | ❌ | Tsonic용 패키지만 |
| 런타임 reflection | ❌ | NativeAOT 제약 |
eval, 동적 코드 실행 | ❌ |
[💡 잠깐! 이 용어는?] Closed-world 분석: 프로그램에서 사용될 수 있는 모든 코드를 컴파일 타임에 알고 있다는 가정. NativeAOT가 동작하는 방식이며, 런타임에 새 코드를 로딩하는 동적 패턴과 충돌한다.
.NET 생태계와의 상호 운용
Tsonic의 흥미로운 부분은 .NET 라이브러리를 직접 사용할 수 있다는 점이다.
import { System } from '@tsonic/dotnet/system'
import { File } from '@tsonic/dotnet/system.io'
// .NET File API를 TypeScript에서 직접 사용
const content = File.ReadAllText('./data.txt')
System.Console.WriteLine(content)TypeScript 문법을 유지하면서 NuGet 패키지와 .NET 표준 라이브러리에 접근할 수 있다.
언제 쓸 수 있을까
현재 Tsonic은 실험적 단계다. GitHub Stars 161개, MIT 라이선스로 공개됐다. 프로덕션에 쓸 수준은 아니지만, 관심을 가질 만한 시나리오는 있다.
| 시나리오 | 적합도 | 이유 |
|---|---|---|
| .NET 팀에 TypeScript 인터페이스 제공 | 높음 | 상호 운용 강점 |
| CLI 도구 네이티브 배포 | 중간 | 런타임 불필요 |
| 고성능 서버 애플리케이션 | 낮음 (현재) | 생태계 미성숙 |
| 일반 웹 서비스 | 낮음 | 오버엔지니어링 |
마무리
Tsonic은 "TypeScript를 그대로 쓰면서 네이티브 성능을 얻을 수 있을까"라는 질문에 대한 하나의 실험 답안이다. C#을 중간 타겟으로 삼은 아이디어가 독특하고, .NET 생태계와의 연결은 특정 팀에게 실용적인 가치가 있다. 지금 당장 프로덕션에서 쓸 도구는 아니지만, TypeScript 컴파일 대상이 브라우저/Node.js를 넘어 확장되는 흐름 중 하나로 주목할 만하다.
참고:
같은 카테고리 · TypeScript
비슷한 주제의 최신 글
태그가 겹치는 글
공통 태그가 많을수록 위에 보인다