背景
react.dev の公式チュートリアルをやってみました。 hooks
にも対応しており良いです。ただしローカル環境構築や TypeScript
関連の案内は無く、相変わらず不親切でした。
html/css/jsx の記述を高速化できる Emmet に興味を持って、
Emmet を題材としてアプリの作成を考えています
。
react.dev を読む
TypeScript + React に入門していきます。
Quick Start
Quick Start
では、簡単な例を通して基礎概念の説明がありました:
- component: UI の部品
- hooks: 状態や副作用を含むロジック
- props: 親 component から子 component に渡されるデータ
データを複数の component で共有する場合は、まず親が useState
で状態を作り、子へ
state を props として渡します。 State を書き換えた場合、変更が伝播して自動的に再度 rendering
が走ります。
Tutorial: Tic-Tac-Toe の環境構築
Tutorial: Tic-Tac-Toe
ではフレームワークなしで React
を使っています。しかしローカル環境の構築方法は示されていません。
create-react-app
は deprecated
になっていますし、いきなり宙ぶらりんになりました。
プロジェクトの作成 (vite
)
今回は vite を使ってみました。 Web
開発におけるビルドツールの 1 つだと思えば良さそうです。
プロジェクトを作成します:
npm create vite@latest
実行
$ npm create vite@latest
✔ Project name: … react-tic
✔ Select a framework: › React
✔ Select a variant: › TypeScript
Scaffolding project in /home/tbm/dev/ts/react-tic...
Done. Now run:
cd react-tic
npm install
npm run dev
指示通りのコマンド実行で dev server (localhost:5173
)
も起動しました。順調です。
TypeScript の種類
言語選択は TypeScript にしました。 TypeScript +
SWC (Speedy Web Compiler) というのもあるようです。
参考. ビルドツールのレイヤ区分
vite
は
esbuild
の上に作られているようです。以下の記事が分かりやすかったです:
JavaScriptビルドツールの整理 各ツールの機能と依存関係
ファイル内容の確認
npm create vite@latest
によって以下のファイルが生成されました:
プロジェクト構成
.
├── README.md
├── index.html # ルート
├── package-lock.json
├── package.json # 依存パッケージ、コマンド定義など
├── public # 静的アセット (TS からの参照無し)
│ └── vite.svg
├── src # ソース
│ ├── App.css
│ ├── App.tsx
│ ├── assets # 静的アセット (TS からの参照あり)
│ │ └── react.svg
│ ├── index.css
│ ├── main.tsx
│ └── vite-env.d.ts # Vite の環境設定 (?) (公式ドキュメント参照)
├── tsconfig.json # TypeScript の設定 (言語のバージョンなど)
└── vite.config.ts # Vite の設定ファイル
以下では特に重要な設定ファイルの内容を確認します。
package.json
Node.js の設定ファイルです。主な初期設定はここに載っています:
package.json
{
"name": "react-tic",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17",
"@typescript-eslint/eslint-plugin": "^6.14.0",
"@typescript-eslint/parser": "^6.14.0",
"@vitejs/plugin-react": "^4.2.1",
"eslint": "^8.55.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5",
"typescript": "^5.2.2",
"vite": "^5.0.8"
}
}
-
scripts
npm run <サブコマンド名>
で実行されるコマンドを定義します。たとえばnpm run dev
を実行すると、vite
コマンドが実行されることが分かります。
-
dependencies
ビルドと実行時に使用されるパッケージです。手動で追加する際はnpm i <パッケージ名>
を使います。
-
devDependencies
ビルドに使用されるパッケージです。手動で追加する際はnpm i -D <パッケージ名>
を使います。
tsconfig.json
TypeScript の設定ファイルです。
プロを目指す人のための TypeScript 入門
第九章の通り、追加でオプションを有効化しました:
tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
- "noFallthroughCasesInSwitch": true
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedIndexedAccess": true,
+ "exactOptionalPropertyTypes": true,
+ "noImplicitReturns": true,
+ "noImplicitOverride": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
セットアップ
Tutorial: Tic-Tac-Toe は JS
で書かれていますが、 TypeScript を使って写経します。初期状態と対応させるため、
App.tsx
を丸ごと書き換えます:
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
export default function Square() {
return <button className="square">X</button>;
}
これで
localhost:5173
を開くと、『X』印が表示されるだけの画面となりました。チュートリアルの環境に追いつけました。
追加ツールの導入
volta
volta は JavaScript に対する rustup
や
ghcup
のようなツールです。
-
インストール (
volta install <tool>
)
node
やnpm
をインストールできます。
-
バージョン固定
volta pin <tool>
によりpackage.json
に node のバージョンを表記できます:
{ + "volta": { + "node": "20.11.0", + "npm": "10.4.0" + } }
-
シェルへの hook (
volta setup
)
direnv
のように、自動的に現プロジェクトのnode
をPATH
に入れてくれます。
言語サーバ
typescript-language-server
を使っています。
prettier
強い (aggressive な) フォーマットを実施するために導入しました。
{
"scripts": {
+ "format": "prettier --write 'src/**/*.{js,jsx,ts,tsx}'",
},
"devDependencies": {
+ "prettier": "^3.2.4",
}
}
{
"singleQuote": true,
"semi": true,
"tabWidth": 2,
}
Emmet
Emacs においては
emmet-mode を導入すると、
emmet-expand
(C-j
) によってサクサク html/css/tsx
を書けるようになります。
たとえば div
は <div></div>
に展開され、
Square/
は
<Square />
に展開されます。ネストしたデータも記述できる他、構造的編集が可能になるようです。
Typedoc
TypeDoc は (大体) TSDoc
形式のコメントを元に
Example
にあるようなサイトを生成してくれます。
$ npm i -D typedoc
{
"scripts": {
"dev": "vite",
"doc": "npx typedoc src/main.tsx --skipErrorChecking",
},
"devDependencies": {
+ "typedoc": "^0.25.7",
}
}
TypeDoc の出力には export
された関数のみが表示されます:
export { default as Game } from './App.tsx';
export * from './App.tsx';
default export
関数が余分な概念に見えて仕方がありません。 TypeScript Deep Dive にも Avoid Export Default とあるので、禁止してみます。
他の関数へリンクするには、
{@link <name>}
という冗長な形式を使用します:
/** Properties of {@link Square}. */
export type SquareProps = {
value: string;
isFocused: boolean;
onSquareClick: () => void;
};
その他は
【TypeScript】そろそろ TSDoc を始めてみる - AI can fly !!
などが詳しそうです。
Tutorial: Tic-Tac-Toe の実践
コンポーネントの型表記
公式チュートリアルでは JavaScript が使用されていますが、もちろん TypeScript
を使いたいので翻訳が必要です。
おそらくコンポーネントの型はこう書きます:
違いました (FC
使用版)
import { FC } from 'react';
/** Properties of {@link Square}. */
export type SquareProps = {
value: string;
isFocused: boolean;
onSquareClick: () => void;
};
const Square: FC<SquareProps> = ({ value, isFocused, onSquareClick }) => {
/* ~~ */
}
訂正:
Function Components | React TypeScript Cheatsheets
によると、 FC
は古く、以下の書き方が新しいようです:
/** Properties of {@link Square}. */
export type SquareProps = {
value: string;
isFocused: boolean;
onSquareClick: () => void;
};
const Square = ({
value,
isFocused,
onSquareClick,
}: SquareProps): React.JSX.Element => {
/* .. */
}
後はゴリゴリやるだけです……!
TypeScript のメモ
- 配列の
map
が fuse せず、都度 copy を作ってしまうようです - range syntax が無くて困っています
まとめ
TypeScript と React に入門し、基本的なツールをセットアップしました。ここまで 4
日です。まだ圧倒的に知識不足ですから、試行回数を増やしたいです。