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
22
7.4k
tsconfig.jsonの設定を見直そう! フロントエンド向け 2024夏
2024-08-06 TSKaigi サブイベント #1 フロントエンド
uhyo
August 06, 2024
Tweet
Share
More Decks by uhyo
See All by uhyo
非同期処理を活用しながらRust製wasmとJSを連携する方法(wasm-bindgenを使いたくない人向け)
uhyo
4
3.1k
React 19を概念から理解する
uhyo
21
9k
require(ESM)とECMAScript仕様
uhyo
6
1.7k
TypeScript Quiz (Encraft #12 Frontend Quiz Night)
uhyo
8
1.6k
Shadow DOMとCSSの現状
uhyo
11
6.9k
TypeScriptってどんな言語? 言語そのものを知る面白さ
uhyo
16
8.7k
App Router時代のデータ取得アーキテクチャ
uhyo
48
15k
ステート管理を超えるRecoil運用の考え方
uhyo
15
12k
ついに来る!TypeScript5.0の新機能
uhyo
21
16k
Other Decks in Technology
See All in Technology
四国のあのイベントの〇〇システムを45日間で構築した話 / cloudohenro2024_tachibana
biatunky
0
300
Oracle Base Database Service:サービス概要のご紹介
oracle4engineer
PRO
0
13k
より快適なエラーログ監視を目指して
leveragestech
3
990
アプリをリリースできる状態に保ったまま 段階的にリファクタリングするための 戦略と戦術 / Strategies and tactics for incremental refactoring
yanzm
6
450
RAGHack: Kickoff and RAG 101
pamelafox
0
290
LLVM/ASMを使った有限体の高速実装
herumi
0
110
Segment Anything Model 2
tenten0727
2
450
Functional TypeScript
naoya
10
4.5k
ロボットアームを遠隔制御の話 & LLMをつかったIoTの話もしたい
soracom
PRO
1
250
OR学会2024秋_短期収益と将来のオフ方策評価性能を考慮したクーポン割当方策混合比の決定
recruitengineers
PRO
4
400
JEP 480: Structured Concurrency
aya_ebata
0
120
AIで変わるテスト自動化:最新ツールの多様なアプローチ/ 20240910 Takahiro Kaneyama
shift_evolve
0
180
Featured
See All Featured
Side Projects
sachag
451
42k
A Modern Web Designer's Workflow
chriscoyier
691
190k
GraphQLとの向き合い方2022年版
quramy
43
13k
What the flash - Photography Introduction
edds
67
11k
Fashionably flexible responsive web design (full day workshop)
malarkey
401
65k
Fantastic passwords and where to find them - at NoRuKo
philnash
48
2.8k
Optimising Largest Contentful Paint
csswizardry
29
2.8k
A designer walks into a library…
pauljervisheath
201
24k
The Straight Up "How To Draw Better" Workshop
denniskardys
230
130k
A better future with KSS
kneath
235
17k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
226
52k
Faster Mobile Websites
deanohume
304
30k
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