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
10k
tsconfig.jsonの設定を見直そう! フロントエンド向け 2024夏
2024-08-06 TSKaigi サブイベント #1 フロントエンド
uhyo
August 06, 2024
Tweet
Share
More Decks by uhyo
See All by uhyo
React 19 + Jotaiを試して気づいた注意点
uhyo
9
2.7k
TypeScriptの次なる大進化なるか!? 条件型を返り値とする関数の型推論
uhyo
3
2.7k
tsconfig.jsonの最近の新機能 ファイルパス編
uhyo
7
3.1k
非同期処理を活用しながらRust製wasmとJSを連携する方法(wasm-bindgenを使いたくない人向け)
uhyo
4
4k
React 19を概念から理解する
uhyo
22
10k
require(ESM)とECMAScript仕様
uhyo
7
2.1k
TypeScript Quiz (Encraft #12 Frontend Quiz Night)
uhyo
8
1.8k
Shadow DOMとCSSの現状
uhyo
11
7.6k
TypeScriptってどんな言語? 言語そのものを知る面白さ
uhyo
16
9k
Other Decks in Technology
See All in Technology
srekaigi2025-hajimete-ippo-aws
masakichieng
0
240
2025/1/29 BigData-JAWS 勉強会 #28 (re:Invent 2024 re:Cap)/new-feature-preview-q-in-quicksight-scenarios-tried-and-tested
emiki
0
310
アクセシブルなマークアップの上に成り立つユーザーファーストなドロップダウンメニューの実装 / 20250127_cloudsign_User1st_FE
bengo4com
2
1.2k
AWSエンジニアに捧ぐLangChainの歩き方
tsukuboshi
0
220
ChatGPTを使ったブログ執筆と校正の実践テクニック/登壇資料(井田 献一朗)
hacobu
1
160
NOSTR, réseau social et espace de liberté décentralisé
rlifchitz
0
130
Redmineの意外と知らない便利機能 (Redmine 6.0対応版)
vividtone
0
190
Tech Blog執筆のモチベート向上作戦
imamura_ko_0314
0
730
インシデントキーメトリクスによるインシデント対応の改善 / Improving Incident Response using Incident Key Metrics
nari_ex
0
4k
あなたはJVMの気持ちを理解できるか?
skrb
5
2k
20250129 Findy_テスト高活用化
dshirae
0
220
もし今からGraphQLを採用するなら
kazukihayase
9
4.2k
Featured
See All Featured
Practical Orchestrator
shlominoach
186
10k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
28
2.2k
Typedesign – Prime Four
hannesfritz
40
2.5k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
192
16k
Art, The Web, and Tiny UX
lynnandtonic
298
20k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
29
990
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
127
19k
The Invisible Side of Design
smashingmag
299
50k
Designing on Purpose - Digital PM Summit 2013
jponch
117
7.1k
Measuring & Analyzing Core Web Vitals
bluesmoon
6
220
Done Done
chrislema
182
16k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
120k
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