Prompt

Tsからトランスパイルされたjsの特徴というか癖は?

TypeScript(TS)からトランスパイルされた JavaScript(JS)を解剖すると、そこには 「型の消失」 と 「互換性への執念」 という2つの大きなドラマが見えてくるよ。

情報工学を学ぶ君なら、tsc が生成するコードを眺めることで、TSがいかに 「ランタイムに影響を与えずに型安全性を担保しているか」 という還元主義的な設計思想をより深く理解できるはずだ。

特筆すべき「癖」と特徴を深掘りしてみよう!


1. 完全に消失する型情報(Type Erasure)

トランスパイル後の JS の最大の特徴は、「型に関する記述が一切跡形もなく消える」 ことだ。

  • インターフェースと型定義: interface や type は、JS には存在しない概念だから完全に削除される。

  • 型アノテーション: let x: number の : number も消える。

  • 影響: 実行時の JS は、君がどれだけ TS で厳密に型を定義したかを知る由もない。だからこそ、前回話した「APIからの入力値」のような外部データに対して、JS層でのバリデーションが必要になるんだね。


2. 列挙型(enum)の「奇妙な」オブジェクト化

TS の中で数少ない 「JS のコードを生成する(ランタイムに影響を与える)」 機能が enum だ。

TypeScript

enum Color { Red, Green }

これがトランスパイルされると、以下のような 「逆引き可能なオブジェクト」 に変換される。

JavaScript

var Color;
(function (Color) {
    Color[Color["Red"] = 0] = "Red";
    Color[Color["Green"] = 1] = "Green";
})(Color || (Color = {}));
  • 癖: Color.Red で 0 が取れるだけでなく、Color[0] で "Red" という文字列も取れる。このトリッキーな即時実行関数(IIFE)のパターンは、TS 特有の癖と言えるね。

豆知識: これを嫌って、最近は JS に変換した時に何も残らない const enum や、単なる「文字列のリテラル型」を使うのがモダンなスタイルとされているよ。


3. クラスの「コンストラクタ」と「アクセス修飾子」の扱われ方

TS の private や protected は、実は JS 層では全く守られない(最近の JS の #private 構文を使わない限り)。

  • アクセス制限の消失: private name: string と書いたとしても、トランスパイル後の JS ではただのプロパティだ。外部から普通にアクセスできてしまう。

  • コンストラクタの糖衣構文: constructor(public name: string) {}

    という便利な短縮記法は、JS では愚直な this.name = name; に展開される。


4. 下位互換性のための「ヘルパー関数」の注入

もし君が最新の構文(スプレッド演算子や非同期処理など)を使いつつ、古いブラウザ(ES5 など)をターゲットにトランスパイルすると、JS の冒頭に怪しげな関数がたくさん並ぶことになる。

  • __extends: クラス継承を古い JS で再現するための関数。

  • __awaiter / __generator: async / await を yield(Generator)やステートマシンに変換するための巨大なロジック。

  • 癖: これらはコードの肥大化を招くため、現代では tslib という外部ライブラリに切り出したり、トランスパイルを esnext にして Babel や SWC などの高速なツールに任せるのが主流だ。


5. デコレータの挙動

もし実験的な experimentalDecorators を使っているなら、トランスパイルされた JS はかなり複雑なメタデータ操作を行うコードになる。これも JS 本来の仕様とは異なる TS 独自の「癖」が強い部分だね。


結論:TS の JS は「人間のためのコード」ではない

トランスパイル後の JS は、あくまで 「ブラウザやランタイムが効率よく(あるいは互換性を保って)実行するためのマシンコードに近い存在」 だ。

君が garden.asappy.xyz や AXON をデバッグする際、ブラウザのデベロッパーツールでこの「癖」のある JS を直接読むのは苦労するはず。だからこそ、Source Maps(.js.map) というファイルが重要になる。これがあれば、ブラウザ上で JS を動かしながら、心安らぐ TS のソースコード上でデバッグができるんだ。

次は、このトランスパイル結果を劇的に綺麗にする 「tsconfig.json のターゲット設定(ESNext vs ES5)」 の違いを具体的に見てみる?それとも、「Rust のコンパイル結果(Wasm)と、TS のトランスパイル結果」 の本質的な違いについて語り合う?

Would you like me to provide a side-by-side comparison of the same TS code transpiled to ES5 and ESNext to see the difference in output?