TypeScriptを5.4に上げるまでの過程

:::note
TypeScriptのバージョン：`4.9`
Nodeのバージョン：`18`
Vite、terserを使用しています
:::

# 1. 背景
業務のコードでTypeScriptを採用しています。

バージョンは`4.9`です。

現在TypeScriptは`5.4.5`が最新です。
ますます差が大きくなると上げづらくなる為、上げることになりました。

# 2. TypeScriptの破壊的変更を整理
## 5.0

https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#breaking-changes-and-deprecations

### 関係演算子における暗黙の強制演算を禁止

TypeScriptの一部の操作では、暗黙の文字列から数値への強制を引き起こす可能性のあるコードを書くと、すでに警告が表示されます

```ts
function func(ns: number |string) {
return ns * 4; // Error, possible implicit coercion
}
```

5.0では、関係演算子 `>`, `<`, `<=`, `>=` にも適用されます。

```ts
functionfunc(ns: number |string) {
return ns > 4; // Now also an error
}

```

必要であれば、 `+` を使って明示的にオペランドを `number` に強制することができます

```ts
functionfunc(ns: number |string) {
return +ns > 4; // OK
}
```

## 5.1

https://devblogs.microsoft.com/typescript/announcing-typescript-5-1/#breaking-changes

### ES2020とNode.js 14.17が最低ランタイム要件

TypeScript 5.1では、ECMAScript 2020で導入されたJavaScriptの機能が実装されています。
TypeScriptがNode.js 14.17以降でしか動作しないです。

## 5.2

https://devblogs.microsoft.com/typescript/announcing-typescript-5-2/#breaking-changes-and-correctness-fixes

### 最近のNode.jsの設定では、`module`と`moduleResolution`が一致していなければならない

`-module nodenext`を単独で使うか、`-module esnext --moduleResolution bundler`を使った方がいいそうです。

```ts
"module": "ESNext",//esmodule と呼ばれるモジュール読み込みの解決方法
"moduleResolution":"bundler",//imports の相対パスにファイル拡張子を要求しない、変更してもファイルパスは既存のままでOK
```

https://www.typescriptlang.org/tsconfig/#moduleResolution

https://expfrom.me/tsconfig-main-property/

## 5.3

https://devblogs.microsoft.com/typescript/announcing-typescript-5-3/#breaking-changes-and-correctness-improvements

### インスタンス・プロパティに対する `super` アクセスのチェック
super.プロパティアクセスによって参照される宣言がクラスフィールドである場合にエラーを出すようになりました。

:::note
5.3以前でもエラーが出ているのでもう少し調査してみます🙇‍♂️
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405182/f5ba8d11-4b87-7b54-8f32-352c388b5ddb.png)

## 5.4

https://devblogs.microsoft.com/typescript/announcing-typescript-5-4/

破壊的変更はなかったです。

# 3. TypeScriptとVite関連のライブラリの関係から設定ファイルの設定値を検討

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405182/7ca1966f-a5a8-29da-4b9f-4ef17e17bce7.png)

頭を整理するために図で関係するライブラリ、設定系を記載しました。

## 3.1. `target`

`es2020`にしました

### 経緯

現状の設定:`ES6`

nodeのバージョンで利用可能なECMAScript機能のベースラインサポートを知ることができるそうです。
[Node Target Mapping](https://github.com/microsoft/TypeScript/wiki/Node-Target-Mapping#node-18)

:::note
適切なECMAScriptのバージョンを指定することでTypeScriptのコンパイルを可能な限り少なくできます
:::

候補
- es2022
    クロスブラウザで使用可能のような記述が以下の記事でありましたが。それが定かかわからなかったのでcan i useで機能ごとに見ると、すると問題ないことがわかりました
    - [正式仕様リリース！ JavaScriptの最新仕様ES2022で追加された「全」新機能](https://zenn.dev/tonkotsuboy_com/articles/es2022-whats-new)
    - [can-i-use-references](https://gist.github.com/Julien-Marcou/156b19aea4704e1d2f48adafc6e2acbf#can-i-use-references)

- ESNext
    - TypeScriptのバージョンがサポートする最も高いバージョン
    - [異なるTypeScriptのバージョン間で同じ意味ではないため、アップグレードの予測が困難になる可能性があるそうです](https://www.totaltypescript.com/tsconfig-cheat-sheet#:~:text=target%3A%20The%20version%20of%20JavaScript%20you%27re%20targeting.%20I%20recommend%20es2022%20over%20esnext%20for%20stability.)

:::note
ここで気づいたのですが、

minifyでterserを使用していました。

terserでecma2020までのものしかminifyされない為、今回はes2020にしました。
[ecmaの型](https://github.com/terser/terser/blob/master/tools/terser.d.ts#L5)
```ts
terserOptions: {
        ecma:2020,
},
```
:::

## 3.2. `module`
`es2020`にしました。

### 経緯

現状の設定:`CommonJS`

[バンドルされるコードにはpreserveかesnextを指定する](https://www.typescriptlang.org/tsconfig/#module:~:text=Sets%20the%20module%20system%20for%20the%20program.%20See%20the%20theory%20behind%20TypeScript%E2%80%99s%20module%20option%20and%20its%20reference%20page%20for%20more%20information.%20You%20very%20likely%20want%20%22nodenext%22%20for%20modern%20Node.js%20projects%20and%20preserve%20or%20esnext%20for%20code%20that%20will%20be%20bundled.)と書かれていました。

esnextはTypeScriptのバージョンによって異なるため、今回は`es2020`と指定しています。
CommonJSスタイルで書かないため、`preserve`は採用しませんでした。

## 3.3. `moduleResolution`
`Bundler`にしました。

### 経緯
現状の設定:デフォルトの設定

バンドラを使用している為です。
node16 や nodenext のように、このモードは package.json の "imports" と "exports" をサポートしますが、Node.js の解決モードとは異なり、`Bundler は imports のパスにファイル拡張子を要求しません`。

[TypeScript で"moduleResolution": "Node"は使わないほうがいい](https://blog.s2n.tech/articles/dont-use-moduleresolution-node)

[Module Resolution](https://www.typescriptlang.org/tsconfig/#moduleResolution:~:text=%27bundler%27%20for%20use%20with%20bundlers.%20Like%20node16%20and%20nodenext%2C%20this%20mode%20supports%20package.json%20%22imports%22%20and%20%22exports%22%2C%20but%20unlike%20the%20Node.js%20resolution%20modes%2C%20bundler%20never%20requires%20file%20extensions%20on%20relative%20paths%20in%20imports)

# 4. targetをes2020に変更して出たエラー

## オブジェクトリテラルのキーの重複時にエラー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405182/45e45f62-c37b-08b2-4a2f-629b268145f7.png)

## 8進数のエスケープシーケンスでエラー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405182/fc46433d-10e8-3d7e-cd55-ac67a035f5d4.png)

# 5. `useDefineForClassFields`を`true`にする

これをtrueにしないとトランスパイル時に、ブラウザで対応されてない[静的初期化ブロック](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Classes/Static_initialization_blocks)が書かれてしまいエラーになる恐れがあるらしいです。

[viteの説明](https://vitejs.dev/guide/features.html#target:~:text=set%20if%20needed.-,useDefineForClassFields,or%20set%20useDefineForClassFields%20to%20true%20explicitly%20when%20configuring%20tsconfig.json.,-Other%20Compiler%20Options)

これを`true`にすると子クラスで親クラスのプロパティを上書きしようとしている際にエラーが出るようになリます。

```ts
class A {
    value: number
}

class B extends A {
    value: number
}
```

![スクリーンショット 2024-06-02 13.28.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405182/26c1b6dc-d5a8-e153-c729-c838bc3224f8.png)

[useDefineForClassFields](https://www.typescriptlang.org/tsconfig/#useDefineForClassFields)

# 6. ビルド後のファイルを見る

ここでビルド後のファイルを見て意図していない変換がされていないか確認します。

# 7. 参考
- [tsconfig.jsonを設定する](https://typescriptbook.jp/reference/tsconfig/tsconfig.json-settings)
- [tsconfig-cheat-sheet](https://www.totaltypescript.com/tsconfig-cheat-sheet)
- [【JavaScript】ES2022の新機能](https://qiita.com/rana_kualu/items/8bafecd760ae69cfac41)
- [Typescript confusion: tsconfig.json module, moduleResolution, target & lib explained](https://medium.com/@tommedema/typescript-confusion-tsconfig-json-module-moduleresolution-target-lib-explained-65db2c44b491)
- [TypeScriptの設定の良し悪し](https://gist.github.com/azu/56a0411d69e2fc333d545bfe57933d07)
- [【TypeScript】tsconfig.jsonの主なオプションについて](https://expfrom.me/tsconfig-main-property/)
- [TypeScriptのmoduleオプションの話、あるいはTypeScript開発者の苦悩、あるいはCJSとESMの話](https://zenn.dev/uhyo/articles/typescript-module-option)

# 8. 最後に
`tsconfig`の設定値や、`vite.config`の設定を知る機会になりました

本記事を読んで頂き、ありがとうございました。
いいねいただけると記事執筆の励みになりますので、参考になったと思われた方は是非よろしくお願い致します🙏