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
12k
tsconfig.jsonの設定を見直そう! フロントエンド向け 2024夏
2024-08-06 TSKaigi サブイベント #1 フロントエンド
uhyo
August 06, 2024
Tweet
Share
More Decks by uhyo
See All by uhyo
libsyncrpcってなに?
uhyo
0
310
Next.jsと状態管理のプラクティス
uhyo
7
5.8k
10ヶ月かけてstyled-components v4からv5にアップデートした話
uhyo
5
600
更新系と状態
uhyo
8
3.1k
React 19アップデートのために必要なこと
uhyo
8
2.4k
color-scheme: light dark; を完全に理解する
uhyo
8
660
React 19 + Jotaiを試して気づいた注意点
uhyo
9
3.4k
TypeScriptの次なる大進化なるか!? 条件型を返り値とする関数の型推論
uhyo
3
3.2k
tsconfig.jsonの最近の新機能 ファイルパス編
uhyo
8
4.4k
Other Decks in Technology
See All in Technology
Lakebaseを使ったAIエージェントを実装してみる
kameitomohiro
0
180
データ基盤からデータベースまで?広がるユースケースのDatabricksについて教えるよ!
akuwano
3
160
Copilot coding agentにベットしたいCTOが開発組織で取り組んだこと / GitHub Copilot coding agent in Team
tnir
0
150
DatabricksにOLTPデータベース『Lakebase』がやってきた!
inoutk
0
150
オフィスビルを監視しよう:フィジカル×デジタルにまたがるSLI/SLO設計と運用の難しさ / Monitoring Office Buildings: The Challenge of Physical-Digital SLI/SLO Design & Operation
bitkey
1
350
United airlines®️ USA Contact Numbers: Complete 2025 Support Guide
unitedflyhelp
0
340
スタックチャン家庭用アシスタントへの道
kanekoh
0
110
Claude Code に プロジェクト管理やらせたみた
unson
8
5k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
55
22k
60以上のプロダクトを持つ組織における開発者体験向上への取り組み - チームAPIとBackstageで構築する組織の可視化基盤 - / sre next 2025 Efforts to Improve Developer Experience in an Organization with Over 60 Products
vtryo
3
980
ゼロからはじめる採用広報
yutadayo
4
1k
アクセスピークを制するオートスケール再設計: 障害を乗り越えKEDAで実現したリソース管理の最適化
myamashii
1
340
Featured
See All Featured
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
50
5.5k
The Cult of Friendly URLs
andyhume
79
6.5k
Why Our Code Smells
bkeepers
PRO
336
57k
Building Better People: How to give real-time feedback that sticks.
wjessup
367
19k
Imperfection Machines: The Place of Print at Facebook
scottboms
267
13k
Making Projects Easy
brettharned
116
6.3k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
Facilitating Awesome Meetings
lara
54
6.5k
A better future with KSS
kneath
238
17k
Thoughts on Productivity
jonyablonski
69
4.7k
Building Applications with DynamoDB
mza
95
6.5k
Music & Morning Musume
bryan
46
6.7k
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