콘텐츠로 바로가기

Modern Languages & Interop (TS-Kotlin)

Modern Languages 및 Interop (TS-Kotlin)의 정의, 범위, 선행 지식, 학습 주제, 참고 근거를 정리한 CS&E 학습 노드입니다.

Article
M

Me

hyunyoun's Blog

programming-languages-compilersprogramming-languagescompilersruntime-systemsmemory-managementmodern-languagesinterop-ts-kotlinlanguages-compilers9 min read

1. Overview

현대 언어의 진화와 런타임 상호운용성(Modern Languages & Interoperability: TS & Kotlin)은 레거시 언어(JavaScript, Java)의 큰 런타임 생태계를 유지하면서, 그 위에 정적 타입 시스템과 현대적 패러다임을 더한 프론트엔드/백엔드 컴파일러의 설계 철학을 다룹니다.

학습자는 JavaScript로 트랜스파일(Transpile)되는 **TypeScript의 구조적 서브타이핑(Structural Subtyping)**과 점진적 타이핑(Gradual Typing) 흐름을 살펴봅니다. 나아가 JVM 바이트코드로 컴파일되는 Kotlin의 100% Java 상호운용성(Interoperability), 확장 함수(Extension Functions), Null 안전성(?)의 바이트코드 매핑 전략을 정리합니다. 마지막으로 언어와 IDE를 분리하여 N×M 에디터 지원 비용을 N+M으로 최적화한 **언어 서버 프로토콜(Language Server Protocol, LSP)**의 아키텍처까지 익혀, 프로그래밍 언어가 단순한 문법을 넘어 도구 생태계(Tooling Ecosystem)로 확장되는 과정을 이해합니다.

2. Scope & Boundaries

In-Scope

  • 컴파일 타임 언어 (Compile-to-X Languages): TypeScript → JavaScript 트랜스파일, Kotlin → JVM 바이트코드 컴파일, 타입 소거(Type Erasure).
  • TypeScript 핵심 설계 (TypeScript Design): 구조적 타입(Structural Typing / Duck Typing), 타입 추론, 유니언/교차 타입(Union/Intersection Types), 점진적 타이핑(Gradual Typing).
  • Kotlin 상호운용성 (Kotlin Interop): Java와의 양방향 상호운용, @JvmOverloads / @JvmName, 확장 함수의 정적 메서드 변환(Static Method Translation), Nullabilty 어노테이션 매핑.
  • 언어 생태계 인프라 (Language Infrastructure): LSP(Language Server Protocol), 구문 강조(Syntax Highlighting), AST 기반 자동 완성(Auto-completion).

Out-of-Scope

  • Kotlin Native / Multiplatform (KMP) 심화: JVM을 벗어난 LLVM 컴파일 타겟 상세 → 05-04 Language Platforms 영역으로 위임.
  • 프론트엔드 프레임워크: React + TypeScript, Spring Boot + Kotlin 개발 패턴 → 해당 프레임워크 학습 영역.

Boundaries

  • 구조적 타입(TS) vs 지명적 타입(Kotlin): TypeScript는 구조적 타입 체계로, 두 객체의 구조(프로퍼티 이름/타입)가 같으면 같은 타입으로 취급(Duck Typing). JS 객체 지향의 동적 생태계를 정적 타입 관점에서 모델링합니다. 반면 Kotlin은 지명적(Nominal) 타입 체계로 명시적 상속/구현(implements) 선언이 필요하여, JVM의 엄격한 상속 트리를 준수합니다.

3. Counterexample

  • 타입 소거의 환상과 런타임 취약성 (TypeScript Runtime Illusion): function checkUser(data: any) { if (data instanceof UserInterface) { ... } }. TypeScript의 인터페이스나 타입 선언은 컴파일 단계(트랜스파일)에서 100% 소거(Erasure)되어 순수 JavaScript가 됩니다. 런타임에 JavaScript 엔진은 UserInterface라는 개념을 전혀 모르기 때문에 저 코드는 ReferenceError: UserInterface is not defined로 크래시됩니다. TS 타입 시스템은 런타임 유효성 검사기(Runtime Validator, 예: Zod)를 대체할 수 없습니다.
  • Java-Kotlin 혼용 시 Null Safety 위반 (Platform Type Blindness): Kotlin은 String?String을 구분하지만, Java 라이브러리의 String getName() 메서드를 Kotlin에서 호출하면 Kotlin 컴파일러는 이 값이 Null인지 아닌지 모르는 상태(Platform Type, String!)로 취급합니다. 이를 val name: String = javaObj.getName() (Non-null)로 강제 캐스팅하여 받았을 때, Java에서 null을 반환하면 런타임 NullPointerException이 발생하여 Kotlin의 Null Safety 보장이 깨집니다. Java 측에 @Nullable/@NonNull 어노테이션이 필수입니다.

4. Prerequisites

  • 타입 시스템 (Basic): 정적 타입, 동적 타입, 다형성에 대한 이해. (05-01-02 Type Systems & Static Analysis)
  • JVM 바이트코드 (Recommended): Kotlin이 JVM 런타임을 타겟팅함을 이해. (05-03-03 JVM Core)

5. Learning Map

Sequence Core Cluster Objective & Description Evidence (BoK)
1 Compile-to-X & Type Erasure 대상 런타임(JS/JVM)을 바꾸지 않고 타입만 덧입힌 후 컴파일 타임에 소거하는 설계 철학을 익힙니다. P1
2 TypeScript & Structural Typing 구조가 같으면 같은 타입(Duck Typing)을 컴파일 타임에 검증하는 유연한 점진적 타입 모델을 살펴봅니다. P5
3 Kotlin Interop & Syntactic Magic 확장 함수가 바이트코드에서 첫 번째 인자를 수신자로 받는 정적 함수로 변환되는 상호운용 방식을 살펴봅니다. Industry
4 Language Server Protocol (LSP) 모든 IDE가 단일 언어 서버와 JSON-RPC로 통신하여 자동 완성과 리팩토링을 제공하는 구조를 이해합니다. Industry

6. Learning Topics

Basic

Core Topic 01: 런타임은 그대로, 타입을 덧입히다 (Compile-to-X & Type Erasure)

  • Why to Learn: 새로운 프로그래밍 언어가 성공하려면 독자적인 VM(가상 머신)을 만드는 대신, 기존의 큰 생태계(브라우저 V8, 서버 JVM) 위로 컴파일되는 전략이 왜 유리한지 아키텍처 관점에서 이해하기 위함입니다.
  • What to Learn:
    • Concepts: 트랜스파일러(Transpiler, Source-to-Source Compiler), 타입 소거(Type Erasure), 폴리필(Polyfill), 소스 맵(Source Map).
    • Skills: 컴파일된 결과물(JS, Class)과 원본 코드 매핑.
  • How to Learn:
    • 1단계: 트랜스파일과 소거: const msg: string = "Hello"; (TS) → const msg = "Hello"; (JS). var x: Int = 5 (Kotlin) → int x = 5; (Java Bytecode). 타입 검사는 컴파일러 프론트엔드에서 수행되고, 최종 결과물에서 타입 어노테이션은 소거됨을 살펴봅니다.
    • 2단계: 소스 맵(Source Map): 브라우저/JVM에서 에러 발생 시, 런타임은 JS/Bytecode 라인을 보고하지만 소스 맵을 통해 원본 TS/Kotlin의 어느 줄인지 매핑하여 디버깅 경험을 보존하는 흐름을 살펴봅니다.
  • Implement: 파이썬 정규식 기반 미니 TS-to-JS 트랜스파일러. re.sub(r':\s*[A-Za-z]+(\[\])?', '', source). function add(a: number, b: number): number { return a+b; } 입력 → 타입 힌트가 모두 제거된 순수 JS function add(a, b) { return a+b; } 출력 시뮬레이터.

Core Topic 02: 오리처럼 걷는다면 오리다, TS의 구조적 타이핑 (TypeScript & Structural Typing)

  • Why to Learn: 명시적 implements 상속 구조 없이, JS의 동적 객체 리터럴 생태계에 정적 타입의 안전성을 적용하는 "구조적 서브타이핑(Structural Subtyping)"의 유연성을 이해하기 위함입니다.
  • What to Learn:
    • Concepts: 구조적 타이핑(Duck Typing의 정적 버전), 지명적 타이핑(Nominal Typing, Java/C++ 방식), 인터섹션/유니언 타입(A & B, A | B), 점진적 타이핑(Gradual Typing, any/unknown).
    • Skills: 타입 가드(Type Guard), 고급 유틸리티 타입 설계(Partial, Pick).
  • How to Learn:
    • 1단계: 구조적 타이핑: interface Point {x: number; y: number}. const obj = {x: 1, y: 2, z: 3}; const p: Point = obj;. objPoint를 명시적으로 상속(implements)하지 않았지만, x와 y를 가지고 있으므로(구조적 호환) Point 타입으로 안전하게 취급됨을 살펴봅니다.
    • 2단계: 점진적 타이핑과 any: 레거시 JS 프로젝트를 TS로 이전할 때, 알 수 없는 타입을 any로 두고 점진적으로 타입을 좁혀나가는 마이그레이션 전략. unknown과의 차이(unknown은 타입 검사(Type Guard) 없이 사용 불가)를 비교합니다.
  • Implement: 파이썬 StructuralTypeChecker. 딕셔너리 데이터 {x:1, y:2, z:3}와 타입 명세 {'x': int, 'y': int}. 명세에 정의된 모든 키와 타입이 데이터에 존재하면(초과 프로퍼티 허용) "타입 호환(Pass)"을 판정하는 검사기 로직 구현. 지명적 타이핑(클래스 인스턴스 검사)과의 비교 로깅.

Practical

Core Topic 03: 100% 자바 호환성, Kotlin 바이트코드 매핑 (Kotlin Interop & Syntactic Magic)

  • Why to Learn: "어떻게 Kotlin은 기존 15년 된 Java 스프링 프레임워크와 양방향으로 호출될 수 있는가?" 그 이면에 있는 컴파일러 레벨의 문법적 설탕(Syntactic Sugar)과 바이트코드 변환 방식을 이해하기 위함입니다.
  • What to Learn:
    • Concepts: 상호운용성(Interoperability), 확장 함수(Extension Function) → 정적 메서드(Static Method) 매핑, 프로퍼티(Property) → Getter/Setter 매핑, 컴파일 타임 널 안전성(Null Safety).
    • Skills: @JvmOverloads, @JvmStatic 사용, Kotlin 디컴파일러로 바이트코드 역추적.
  • How to Learn:
    • 1단계: 확장 함수의 변환 방식: Kotlin fun String.lastChar(): Char = this.get(this.length - 1). 기존 String 클래스를 수정하는 것 같지만, 컴파일된 바이트코드는 public static final char lastChar(String $this). 첫 번째 인자로 수신 객체를 받는 정적 메서드일 뿐임을 살펴봅니다.
    • 2단계: Null 안전성 컴파일: val s: String (Non-null). 컴파일 시 메서드 최상단에 Intrinsics.checkNotNullParameter(s, "s"); 바이트코드가 자동 삽입되어, Java 쪽에서 null을 넘기면 로직 실행 전 NullPointerException (더 좁게는 IllegalArgumentException)으로 실패하며 방어하는 흐름을 살펴봅니다.
  • Implement: 파이썬 AST ExtensionFunctionTransformer. String_lastChar(s) 같은 정적 함수 호출로 Kotlin의 확장 함수 메커니즘 흉내내기. s.lastChar() 문법을 파싱하여 AST 레벨에서 lastChar(s) 정적 함수 호출로 변환하는 미니 트랜스파일 패스 구현.

Advanced

Core Topic 04: 에디터와 언어의 디커플링, 언어 서버 프로토콜 (Language Server Protocol, LSP)

  • Why to Learn: 왜 요즘은 VS Code 하나로 수십 가지 언어의 자동 완성, "Go to Definition", 리팩토링이 가능한지, 그 배후에 있는 마이크로소프트의 LSP(Language Server Protocol) 아키텍처를 이해하기 위해서입니다.
  • What to Learn:
    • Concepts: N×M 복잡성 문제, LSP 아키텍처(클라이언트 에디터 ↔ JSON-RPC ↔ 언어 서버), AST 기반 코드 분석.
    • Skills: Language Server 설치(TSServer, gopls, rust-analyzer), JSON-RPC 페이로드 구조 이해.
    • Tools: VS Code, JSON-RPC.
  • How to Learn:
    • 1단계: N×M 복잡성 감소: 과거엔 5개 언어, 5개 에디터가 있으면 25개의 플러그인이 필요. LSP 도입 후, 에디터는 LSP 클라이언트 1개만, 언어는 LSP 서버 1개만 만들면 되는 5+5=10 복잡성 감소 최적화 아키텍처를 살펴봅니다.
    • 2단계: LSP 동작 흐름: 사용자가 user. 타이핑 (에디터 클라이언트) → JSON-RPC textDocument/completion 위치 정보 전송 → 언어 서버(TSServer) 내부 AST 분석하여 메서드 목록 도출 → JSON-RPC 응답 반환 → 에디터 렌더링. 파싱/타입 추론 등 무거운 작업이 별도 프로세스(서버)로 격리되는 흐름을 살펴봅니다.
  • Implement: 파이썬 기반 간단한 미니 LSP 서버(TCP 소켓 기반). JSON-RPC 2.0 포맷 수신 대기. 클라이언트가 {"method": "textDocument/completion", "params": {"text": "sys.", "line": 5}} 전송 시, 파이썬 내장 dir(sys) 결과를 JSON 배열로 응답하는 모의 서버 및 클라이언트(소켓 접속) 송수신 데모.

7. Terminology

Term (EN / ko, abbr) 1문장 정의 단계(기본/권장/실무/심화) 역할/맥락 관련 개념 유사/대비/함께 사용 오해 포인트 Evidence(Primary/Secondary/Industry) Flags(core)
Transpiler (Source-to-Source) TypeScript나 ES6 코드를 브라우저가 이해할 수 있는 하위 버전의 순수 JavaScript 코드로 변환(번역)해주는 프론트엔드 파이프라인 구성 요소입니다. 기본 코드 변환 Babel / tsc Compiler 바이트코드나 기계어로 번역하는 것이 아니라, 다른 프로그래밍 '소스 코드'로 번역함 P1:CS2023 core
Type Erasure TypeScript나 Kotlin이 컴파일(트랜스파일) 타임에만 타입 검사를 수행하고, 최종 생성된 JS나 바이트코드에서는 타입 정보를 완전히 지워버려 런타임 호환성을 유지하는 기법입니다. 권장 호환성 및 최적화 Generics Reified Types 타입 에러는 컴파일 시점에 다 잡히지만, 런타임(실행 중)에는 타입 정보를 꺼내볼 수 없음 P5:SFIA core
Interoperability Kotlin 코드가 기존 Java 라이브러리를 그대로 가져다 쓰거나, TypeScript가 C 기반 WebAssembly 모듈을 호출하는 등 이기종 언어 간의 양방향 호출 호환성입니다. 실무 생태계 통합 FFI (Foreign Function Interface) JNI (Java Native Interface) 완전히 매끄러울 수 없으며, 자료형 매핑이나 가비지 컬렉터 충돌 등 인터페이스 비용이 발생함 Industry core
WebAssembly (Wasm) 브라우저 내에서 자바스크립트의 성능 한계를 극복하기 위해, C/C++, Rust 등으로 짠 코드를 웹에서 네이티브 속도로 돌릴 수 있게 만든 저수준 바이트코드 포맷입니다. 심화 웹 브라우저 한계 돌파 JIT / Sandboxing asm.js 자바스크립트를 아예 대체하는 것이 아니라, 연산이 무거운 핫스팟(Hotspot)만 Wasm으로 넘겨 상호 보완함 Industry core

8. References

Primary

  • [P1] CS2023 - Software Engineering (SE) - Modern Language Ecosystems
  • [P5] SFIA - Systems Integration (SINT) - Interoperability

Secondary

  • [Effective TypeScript] Dan Vanderkam - Type Erasure and JS Interop
  • [Kotlin in Action] Dmitry Jemerov, Svetlana Isakova - Java Interoperability and Null Safety

Industry

  • [TypeScript Handbook] - Type Compatibility, Structural Typing, and Transpilation
  • [WebAssembly Core Specification] - Wasm Execution Model and Memory Isolation

9. Final Checklist

Primary

  • TypeScript가 강력한 타입 시스템을 제공함에도 불구하고, 왜 브라우저 런타임에서는 타입 에러를 잡아낼 수 없는지(Type Erasure) 과정을 설명할 수 있는가?
  • Kotlin이 Java 바이트코드(.class)로 똑같이 컴파일되면서 기존 Spring 프레임워크 생태계에 100% 상호운용될 수 있었던 인터옵(Interop) 전략을 증명할 수 있는가?

Secondary

  • 트랜스파일러(Babel, tsc)가 소스 코드를 AST로 나눈 뒤, 하위 버전의 자바스크립트 구문(Polyfill)으로 치환하여 재조립하는 파이프라인 구조를 묘사할 수 있는가?
  • Kotlin의 널 안전성(Null Safety, ? 연산자)이 컴파일 타임에 Null Pointer Exception을 차단하는 정적 분석 원리를 설명할 수 있는가?

Industry

  • 무거운 이미지 렌더링 함수를 JavaScript 대신 Rust로 작성하여 WebAssembly로 컴파일하고, 이를 웹 프론트엔드에서 인터옵(Interop)으로 호출할 때의 메모리 복사 오버헤드를 논증할 수 있는가?
  • 동적 언어(JS) 생태계에 점진적 타이핑(Gradual Typing)을 도입하기 위해 TypeScript가 사용하는 구조적 타이핑(Structural/Duck Typing)이 엔터프라이즈 마이크로서비스 설계에 주는 안정성을 아키텍처링 할 수 있는가?

Languages Compilers · Language Platforms & Ecosystems

6 / 6