Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
tsconfig.jsonの設定を見直そう!フロントエンド向け 2024夏
Search
uhyo
August 06, 2024
Technology
26
8.8k
tsconfig.jsonの設定を見直そう! フロントエンド向け 2024夏
2024-08-06 TSKaigi サブイベント #1 フロントエンド
uhyo
August 06, 2024
Tweet
Share
More Decks by uhyo
See All by uhyo
TypeScriptの次なる大進化なるか!? 条件型を返り値とする関数の型推論
uhyo
2
1.7k
tsconfig.jsonの最近の新機能 ファイルパス編
uhyo
7
2.3k
非同期処理を活用しながらRust製wasmとJSを連携する方法(wasm-bindgenを使いたくない人向け)
uhyo
4
3.7k
React 19を概念から理解する
uhyo
22
9.7k
require(ESM)とECMAScript仕様
uhyo
6
1.9k
TypeScript Quiz (Encraft #12 Frontend Quiz Night)
uhyo
8
1.7k
Shadow DOMとCSSの現状
uhyo
11
7.3k
TypeScriptってどんな言語? 言語そのものを知る面白さ
uhyo
16
8.9k
App Router時代のデータ取得アーキテクチャ
uhyo
49
16k
Other Decks in Technology
See All in Technology
アジャイルチームがらしさを発揮するための目標づくり / Making the goal and enabling the team
kakehashi
3
160
エンジニア人生の拡張性を高める 「探索型キャリア設計」の提案
tenshoku_draft
1
130
AWS Lambda のトラブルシュートをしていて思うこと
kazzpapa3
2
200
CDCL による厳密解法を採用した MILP ソルバー
imai448
3
180
Exadata Database Service on Dedicated Infrastructure(ExaDB-D) UI スクリーン・キャプチャ集
oracle4engineer
PRO
2
3.2k
Terraform Stacks入門 #HashiTalks
msato
0
360
生成AIが変えるデータ分析の全体像
ishikawa_satoru
0
180
個人でもIAM Identity Centerを使おう!(アクセス管理編)
ryder472
4
240
iOSチームとAndroidチームでブランチ運用が違ったので整理してます
sansantech
PRO
0
150
Next.jsとNuxtが混在? iframeでなんとかする!
ypresto
1
130
Why App Signing Matters for Your Android Apps - Android Bangkok Conference 2024
akexorcist
0
130
LINEヤフーにおけるPrerender技術の導入とその効果
narirou
1
160
Featured
See All Featured
Building an army of robots
kneath
302
43k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
44
6.8k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
26
2.1k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
356
29k
Practical Orchestrator
shlominoach
186
10k
[RailsConf 2023] Rails as a piece of cake
palkan
52
4.9k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
44
2.2k
The Cult of Friendly URLs
andyhume
78
6k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
131
33k
Facilitating Awesome Meetings
lara
50
6.1k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
31
2.7k
Navigating Team Friction
lara
183
14k
Transcript
tsconfig.jsonの設定を⾒直そう! フロントエンド向け 2024夏 2024-08-06 TSKaigiサブイベント #1 フロントエンド
発表者紹介 uhyo 株式会社カオナビ フロントエンドエキスパート 普段はTypeScriptとかReactをやっている。 好きなTSのコンパイラオプションは noUncheckedIndexedAccess (機能に加えて名前の覚えにくさが好き) 2
tsconfig.json TypeScriptのコンパイラオプション等を記述した ファイル。 tscやエディタ等から参照される。 tsc --initによって作成できる。 Next.js等が勝⼿に⽤意してくれる場合もある。 3
tsconfig.jsonのベストプラクティス TypeScriptの進化に伴ってベストプラクティスも 変化を続けている。 今回はフロントエンド向けの設定を中⼼に紹介。 この機会にtsconfig.jsonを点検しましょう。 4
moduleResolution 5
moduleResolution: “bundler” ⼀番フロントエンドに特有なのはこれ。 バンドラを使っている場合に有効な設定。 古い慣習が残っている場合はアップデートしよう。 “moduleResolution”: “node”, “moduleResolution”: “bundler”, 6
moduleResolutionとは その名のとおり、モジュール解決の⽅法を決める。 importで指定されたモジュールが実際にどのファ イルに当たるかを判定するのがモジュール解決。 import … from “react”; → node_modules/react/index.js
import … from “./foo”; → ./foo.ts 7
moduleResolutionの値 (1) 昔からあった2つ: • classic: node_modulesをサポートしていない。 • node: Node.jsのようにnode_modulesからライブラリ を探す挙動をサポート。のちにnode10という別名が
ついた。 8
moduleResolutionの値 (2) • node16/nodenext: Node.js 16以降でのモジュール解 決の挙動を再現するモード。 具体的にはCJS/ESMの区別、package.jsonのexportsの サポートなど。 ESMをインポートするときは拡張⼦を省略できない仕様も再現されている
import … from “./foo.js”; → ./foo.ts 9
moduleResolutionの値 (3) • bundler: webpackなどのバンドラ挙動を再現する モード。package.jsonのexportsをサポート。 Node.js⽤モードとは異なり、ESMの場合でも 相対パスの拡張⼦を書かなくていい。 拡張⼦を省略してもimportできる! import
… from “./foo”; → ./foo.ts 10
moduleResolution: “bundler” 昔から使っているtsconfig.jsonの場合、 とりあえずnode_modulesを使えるモードとして nodeが指定されていることが多い。 ⾒直してみよう。 “moduleResolution”: “node”, “moduleResolution”: “bundler”,
11
baseUrl 12
baseUrlは消そう baseUrlが設定されている場合、多くの場合は不要 なので消しましょう。 “baseUrl”: “./something”, 消す 13
なぜbaseUrlが設定されているのか 昔のバージョン(4.0以前)でpathsを設定する ためにbaseUrlが必須だった名残で指定されている。 今はもうその必要がない。 14
baseUrl設定の弊害 相対パスではない(./で始まらない)指定なのに baseUrlからの相対パス扱いでimportできてしまう (バンドラと設定が合わず怒られがち) import … from “foo/bar/xxx”; → src/foo/bar/xxx.ts
(baseUrlが./srcの場合) 15
target 16
targetの意味知ってますか? targetにはes5とかes2023とかesnextとか 書くことができる。 これは何を指定しているのか分かりますか? “target”: “es5”, 17
targetの意味 コードの実⾏環境がどのバージョンの機能を サポートしているか指⽰する。 • そのバージョンのJSにトランスパイルする • そのバージョンまでの型定義を読み込む • 正規表現でそのバージョンでは使えない構⽂を弾く 例:
/^foo(?<num>¥d+)/.test(str) ← これはes2018未満ではコンパイルエラー 18
targetの注意点 • そのバージョンのJSにトランスパイルする SWCなど別のツールを使っている場合はtargetを⾒ないことも • そのバージョンまでの型定義を読み込む libを別に指定している場合はそちらが優先される • 正規表現でそのバージョンでは使えない構⽂を弾く これはTS
5.5から 19
targetの設定指針 基本的にはコンパイラオプションの意味に忠実に。 動作環境を表す値を設定すべし。 libを別に指定している場合はlibもメンテしよう。 libやtargetがメンテされていないせいで最近の 機能を使えていないコードベースは悲しい。 (配列のflatMapとか) 20
module 21
moduleオプションとは コードがどんなモジュールシステムで動くのかを 指⽰するオプション。 targetからモジュールシステムだけ抜き出して 別のオプションにしたと思えば⼤体合ってる。 (targetはESバージョンに着⽬した指定だが、モジュール システムは環境によって異なることを反映したオプション) 22
moduleオプションの値 歴史的経緯を反映して指定可能な値が⾊々ある。 commonjs es2015 es2020 es2022 esnext amd system umd
node16 nodenext preserve 23
TypeScriptのモジュールシステム (1) TSにおけるimport/exportは、常にES Modules のセマンティクスに従うもの。 moduleをcommonjsにした場合、トランスパイル時に CommonJSに変換される。 import { foo
} from "./foo"; console.log(foo); const foo_1 = require("./foo"); console.log(foo_1.foo); 24
TypeScriptのモジュールシステム (2) ES Modulesとは無関係にただ単にCommonJSの 構⽂へトランスパイルしてほしい時のための TypeScript独⾃構⽂も⽤意されている。 import foo = require("./foo“);
console.log(foo); const foo = require("./foo"); console.log(foo); 25
TypeScriptのモジュールシステム (3) module: “esnext” が設定されている場合、 トランスパイル先がCommonJSに対応していない純粋な ES Modules環境だと解釈されるので、 独⾃構⽂は使⽤不可となる。 import
foo = require("./foo“); console.log(foo); ✖ 26
moduleオプションの指定 “moduleResolution”: “bundler” と組み合わせる 前提だと、moduleの指定は2択。 • “module”: “esnext” • “module”:
“preserve” 27
moduleオプションとバンドラの関係 (1) 今どきのバンドラはES Modulesを解するので、 ES Modulesのみの環境を表すesnextが適切と 考えられていた。 しかし、webpackなどrequireを解するバンドラ もある。また、Bunもimportとrequireを 両⽅サポートしている。
28
moduleオプションとバンドラの関係 (2) これらはimportとrequireを同じファイルで 混ぜられるなど、Node.jsとも異なる 独⾃のモジュール環境であるため、 “module”: “preserve” が与えられた。 29
moduleオプション余談 (1) “module”: “preserve” は、tsconfigが無い 状態でVS Codeが使うデフォルト設定として 導⼊されたという側⾯もある。 旧設定 “module”:
“esnext”, “moduleResolution”: “node” 新設定 “module”: “preserve”, “moduleResolution”: “bundler” 参考: https://github.com/microsoft/TypeScript/pull/56785 30
moduleオプション余談 (2) 旧設定がpackage.jsonのexportsに対応していない といった問題を解消しつつ、Node.js以外の 多様な環境でTSが使われる現状を反映した、 ⾃由度の⾼いデフォルト設定となっている。 旧設定 “module”: “esnext”, “moduleResolution”:
“node” 新設定 “module”: “preserve”, “moduleResolution”: “bundler” 31
tsconfig.json⾒直しポイントまとめ “target”: “es2023”, ← ちゃんとバージョン上げる “module”: “esnext”, ← もしくはpreserve “moduleResolution”:
“bundler”, ← nodeから変える // “baseUrl”: “./…”, ← 残ってたら消す ※ バンドラを⽤いるフロントエンド向けの設定です 32
おまけ―モジュール周りの Node.jsの動きについて 注意: 以降の説明は現状のexperimentalな実装のものであり、 リリースされるまでに内容が変化する可能性があります 33
Node.jsのESMではimportに拡張⼦が必須 “moduleResolution”: “node16”の場合、相対パスでの importは拡張⼦が必須。 また、実際のファイルが.tsでも、 import宣⾔は.jsで書く必要がある。 import { foo }
from “./foo”; → コンパイルエラー発⽣ import { foo } from “./foo.js”; → ./foo.tsに解決される 34
Node.jsのESMではimportに拡張⼦が必須 これは以下の理由で説明される。 • .tsファイルはコンパイル後に.jsファイルになる。 • TSは勝⼿にimport元を書き換えることをしたくないので、 あらかじめコンパイル後の拡張⼦で書く必要がある。 import { foo
} from “./foo”; → コンパイルエラー発⽣ import { foo } from “./foo.js”; → ./foo.tsに解決される 35
ところが…… 最近、Node.jsは.tsファイルを直接実⾏できる機能の 導⼊を検討している。(--experimental-strip-types) とりあえず初期実装は⼊った。 .tsファイルが与えられた場合SWCを使って JSにトランスパイルしてから実⾏する。 参考: https://github.com/nodejs/node/pull/53725 36
Node.jsのTS対応とモジュール解決 なんと、Node.jsのTS対応を利⽤する場合は .tsでimportする必要がある。 既存のNode.js向けTSコードとの互換性を重視せず、 新機能に合わせたコードを書いてもらう設計。 import { foo } from
“./foo.js”; → MODULE NOT FOUND!! import { foo } from “./foo.ts”; → OK (loaderでのモジュール解決がつらくなるのを避けるためという理由が主らしい) 37
Node.jsのTS対応とモジュール解決 デフォルトのTSの設定では.tsをimportすることは 禁⽌されている。 allowImportingTsExtensionsを有効にすれば可能 だが、noEmitも⼀緒に有効にする必要がある。 (事前のトランスパイルが不要でランタイム/バンドラが 直接.tsを解釈できるなら許すという考え⽅) 38
Node.jsのTS対応まとめ 従来のやり⽅(事前にTS→JSトランスパイルする)と 新オプションのやり⽅(Node.jsで直接.tsを実⾏できる) ではimport宣⾔の書き⽅が異なるので、 どちらかを選ぶ必要がある。 コミュニティの分断が⼼配。 39