【TypeScript5.8】erasableSyntaxOnlyフラグが導入されてNodeで動かせるようになる

TypeScriptは基本的に、JavaScriptに型注釈を追加しただけの言語です。

```ts:TypeScript
function hoge(num: number){
    return num+1;
}

hoge(100);   // 101
hoge("100"); // エラー
```

コンパイルすると型関連の文法が削除され、普通のJavaScriptになります。

```js:JavaScript
function hoge(num){
    return num+1;
}

hoge(100);   // 101
hoge("100"); // 1001
```

開発時はコードの間違いを見つけやすく、コンパイルすると普通のJavaScriptになってブラウザから実行可能です。

このようなJavaScriptの上位言語はaltJSと呼ばれ、CoffeeScriptやDartなど様々な言語が開発されました。
ここで多くの言語は正しい言語を目指し、[JavaScriptの異常な挙動](https://qiita.com/rana_kualu/items/793f0cbdde6a88f86394)を排除し、結果としてJavaScriptとは全く異なる言語になりました。
そして、JavaScriptと全く同じ文法のTypeScriptが覇権を握りました。
ユーザは言語の正しさなんてものには興味がないから当然ですね。

とはいえTypeScriptも実際には削除可能コードだけできているわけではなく、TypeScript独自のコードも、特に初期のころは導入されていました。
有名どころではENUMで、これはJavaScriptには全く存在しないので削除するとJavaScriptとして動かなくなってしまいます。

```ts:TypeScript
enum Suit {
  Hearts,
  Diamonds,
  Spades,
  Clubs,
};
const suit = Suit.Clubs;
```

正しく動かすためには変換が必要です。

```js:JavaScript
var Suit;
(function (Suit) {
    Suit[Suit["Hearts"] = 0] = "Hearts";
    Suit[Suit["Diamonds"] = 1] = "Diamonds";
    Suit[Suit["Spades"] = 2] = "Spades";
    Suit[Suit["Clubs"] = 3] = "Clubs";
})(Suit || (Suit = {}));
const suit = Suit.Clubs;
```


ところで[Node.js 22.6.0](https://nodejs.org/ja/blog/release/v22.6.0)で`--experimental-strip-types`というオプションが導入されました。
これはTypeScriptの実行コードから型関連コードを削除するというフラグです。
さらに[23.6.0](https://nodejs.org/ja/blog/release/v23.6.0)ではこれがデフォルトになり、逆に`--no-experimental-strip-types`で否定しない限り常に型関連コードが削除されるようになりました。

すなわち、TypeScriptのコードはNode.jsでそのまま動作します。

ただし、[名前のとおり型を削除するだけ](https://github.com/nodejs/loaders/issues/208)の処理であり、ENUMのような変換が必要なコードには対応していません。
これは実行速度との兼ね合いや、TypeScriptのコードに追随しなければならない危惧を考えた末の妥協点のようです。

そんなわけでNodeとTypeScriptが手を取り合った結果、TypeScript側にも、Nodeで削除可能なコードだけでできているかを確認できるフラグ`erasableSyntaxOnly`が[導入されることになりました](https://devblogs.microsoft.com/typescript/announcing-typescript-5-8-beta/#the---erasablesyntaxonly-option)。

このフラグを有効にしておくと、ENUMや名前空間などの削除可能ではないコードを使うとエラーになります。

すなわち、`erasableSyntaxOnly`で開発したTypeScriptのコードはNode.jsでそのまま動作します。
やったね。


# erasableSyntaxOnlyで許されない構文

## ENUM

上記解説のとおりです。


```ts
enum X { }
```

## namespace

JavaScriptには名前空間がありません。

```ts
namespace X {
  const x = 1;
}
```

## constructorプロパティ割り当て

```ts
class X {
  constructor(public y) { }
}
```

これは単に`public`を消すだけではだめで、[プロパティ`X.y`を生やさないといけない](https://qiita.com/fumiya1753/items/260ea71c5a3d316d1473)ので、削除では対応できません。


## 一部のimport文

```ts
import x = require('fs');
import A = e.p;
```

前者は適切な代替案がいまのところないそうです。


動かなくなる構文は以上のようです。
思ったより少ないですね。
これなら移行にもさほど苦労はしなさそうです。


# erasableSyntaxOnlyでも許される構文

## プロパティ可視性

```ts
class X {
  public y;
}
```

これは`public`を消せば動くのでOKです。


## 空のnamespace

```ts
namespace T {}
```

[削除可能だから許される](https://github.com/microsoft/TypeScript/issues/59601#issuecomment-2294010520)そうです。
何に使うんだろうこれ。


# 感想

実は[class](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Classes)も、元々は[TypeScriptが勝手に実装していた](https://atmarkit.itmedia.co.jp/ait/articles/1301/18/news087_2.html)ものが[ES2015で逆輸入された](https://qiita.com/niisan-tokyo/items/83582bc0646239cf6cb8)という経緯があります。
つまり、下手したらclassすらerasableSyntaxOnlyで排除される可能性があったというわけです。
さすがにclassが使えなかったら致命傷だったと思うので、取り入れられていてよかったですね。

そんなわけで、方針が固まって軌道に乗った後のTypeScriptはともかく、開発当初のTypeScriptは[わりとフリーダム](https://devblogs.microsoft.com/typescript/announcing-typescript-0-9/)だったみたいですね。

なお、なぜかENUMはclassと同じ波に乗れず、TypeScript独自実装のまま現在まで来てしまったわけですがどうしてでしょうか。
[proposalを作っている人はいる](https://github.com/rbuckton/proposal-enum)のですが、TC39では[stage0にすら入ってない](https://github.com/tc39/proposals)んですよね。
よくわかりません。

ということで、今後のTypeScriptはerasableSyntaxOnlyで書いていくようにすると捗ることでしょう。