create-ai-project 1.23.2 → 1.23.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/.claude/agents-en/acceptance-test-generator.md +4 -2
  2. package/.claude/agents-en/code-reviewer.md +3 -0
  3. package/.claude/agents-en/quality-fixer-frontend.md +3 -3
  4. package/.claude/agents-en/quality-fixer.md +3 -3
  5. package/.claude/agents-en/task-decomposer.md +2 -1
  6. package/.claude/agents-en/task-executor-frontend.md +8 -2
  7. package/.claude/agents-en/task-executor.md +8 -2
  8. package/.claude/agents-en/technical-designer-frontend.md +10 -48
  9. package/.claude/agents-en/technical-designer.md +10 -26
  10. package/.claude/agents-en/work-planner.md +2 -5
  11. package/.claude/agents-ja/acceptance-test-generator.md +4 -2
  12. package/.claude/agents-ja/code-reviewer.md +3 -0
  13. package/.claude/agents-ja/quality-fixer-frontend.md +3 -3
  14. package/.claude/agents-ja/quality-fixer.md +3 -3
  15. package/.claude/agents-ja/task-decomposer.md +2 -1
  16. package/.claude/agents-ja/task-executor-frontend.md +8 -2
  17. package/.claude/agents-ja/task-executor.md +8 -2
  18. package/.claude/agents-ja/technical-designer-frontend.md +10 -48
  19. package/.claude/agents-ja/technical-designer.md +9 -25
  20. package/.claude/agents-ja/work-planner.md +2 -5
  21. package/.claude/commands-en/build.md +6 -15
  22. package/.claude/commands-en/front-build.md +4 -13
  23. package/.claude/commands-en/implement.md +2 -15
  24. package/.claude/commands-en/plan.md +7 -2
  25. package/.claude/commands-en/prepare-implementation.md +7 -17
  26. package/.claude/commands-en/sync-skills.md +3 -3
  27. package/.claude/commands-ja/build.md +7 -16
  28. package/.claude/commands-ja/front-build.md +4 -13
  29. package/.claude/commands-ja/implement.md +2 -15
  30. package/.claude/commands-ja/plan.md +6 -1
  31. package/.claude/commands-ja/prepare-implementation.md +8 -18
  32. package/.claude/commands-ja/sync-skills.md +3 -3
  33. package/.claude/skills-en/documentation-criteria/references/plan-template.md +0 -2
  34. package/.claude/skills-en/frontend-technical-spec/SKILL.md +4 -4
  35. package/.claude/skills-en/frontend-typescript-rules/SKILL.md +45 -111
  36. package/.claude/skills-en/frontend-typescript-testing/SKILL.md +8 -6
  37. package/.claude/skills-en/integration-e2e-testing/SKILL.md +2 -0
  38. package/.claude/skills-en/subagents-orchestration-guide/SKILL.md +2 -7
  39. package/.claude/skills-en/task-analyzer/references/skills-index.yaml +9 -11
  40. package/.claude/skills-ja/documentation-criteria/references/plan-template.md +0 -2
  41. package/.claude/skills-ja/frontend-technical-spec/SKILL.md +3 -3
  42. package/.claude/skills-ja/frontend-typescript-rules/SKILL.md +43 -288
  43. package/.claude/skills-ja/frontend-typescript-testing/SKILL.md +15 -71
  44. package/.claude/skills-ja/integration-e2e-testing/SKILL.md +2 -0
  45. package/.claude/skills-ja/subagents-orchestration-guide/SKILL.md +2 -7
  46. package/.claude/skills-ja/task-analyzer/references/skills-index.yaml +10 -11
  47. package/CHANGELOG.md +19 -0
  48. package/package.json +1 -1
@@ -5,132 +5,66 @@ description: Applies React/TypeScript type safety, component design, and state m
5
5
 
6
6
  # TypeScript Development Rules (Frontend)
7
7
 
8
- ## Frontend-Specific Anti-patterns
8
+ Frontend-specific React/TypeScript rules for implementation: thresholds, boundary type safety, component/state design, error handling, and project conventions.
9
9
 
10
- In addition to universal anti-patterns, watch for these Frontend-specific issues:
10
+ ## Anti-patterns and Thresholds
11
+ Signals that trigger a design change:
12
+ - Prop drilling through 3+ levels → lift to Context or state management
13
+ - Component over 300 lines → split
14
+ - Props count over 10 → split the component (3-7 is the working range)
15
+ - Optional props over 50% → introduce defaults or Context
16
+ - Props nesting deeper than 2 levels → flatten
17
+ - The same `as` assertion appearing 3+ times → revisit the type design
11
18
 
12
- - **Prop drilling through 3+ levels** - Should use Context API or state management
13
- - **Massive components (300+ lines)** - Split into smaller components
19
+ ## Type Safety at Boundaries
20
+ Prohibit `any`; when a type is unavailable, receive it as `unknown` and narrow with a type guard. Minimize `as` (justify with a comment when unavoidable).
14
21
 
15
- ## Type Safety in Frontend Implementation
22
+ Inside the app, React Props/State are type-guaranteed — no `unknown` needed. At every external boundary, receive as `unknown` and narrow with a type guard before use: API responses, `localStorage`/`sessionStorage`, URL parameters, parsed JSON. Controlled-component form input stays type-safe through React synthetic events.
16
23
 
17
- **Type Safety in Data Flow**
18
- - **Frontend -> Backend**: Props/State (Type Guaranteed) -> API Request (Serialization)
19
- - **Backend -> Frontend**: API Response (`unknown`) -> Type Guard -> State (Type Guaranteed)
20
-
21
- **Frontend-Specific Type Scenarios**:
22
- - **React Props/State**: TypeScript manages types, unknown unnecessary
23
- - **External API Responses**: Always receive as `unknown`, validate with type guards
24
- - **localStorage/sessionStorage**: Treat as `unknown`, validate
25
- - **URL Parameters**: Treat as `unknown`, validate
26
- - **Form Input (Controlled Components)**: Type-safe with React synthetic events
27
-
28
- **Type Complexity Management (Frontend)**
29
- - **Props Design**:
30
- - Props count: 3-7 props ideal (consider component splitting if exceeds 10)
31
- - Optional Props: 50% or less (consider default values or Context if excessive)
32
- - Nesting: Up to 2 levels (flatten deeper structures)
33
- - Type Assertions: Review design if used 3+ times
34
- - **External API Types**: Relax constraints and define according to reality (convert appropriately internally)
35
-
36
- ## Coding Conventions
37
-
38
- **Component Design Criteria**
39
- - **Function Components (Mandatory)**: Official React recommendation, optimizable by modern tooling
40
- - **Classes Prohibited**: Class components completely deprecated (Exception: Error Boundary)
41
- - **Custom Hooks**: Standard pattern for logic reuse
42
-
43
- **Function Design**
44
- - **0-2 parameters maximum**: Use object for 3+ parameters
45
- ```typescript
46
- // Object parameter
47
- function createUser({ name, email, role }: CreateUserParams) {}
48
- ```
49
-
50
- **Props Design (Props-driven Approach)**
51
- - Props are the interface: Define all necessary information as props
52
- - Avoid implicit dependencies: Do not depend on global state or context without necessity
53
- - Type-safe: Always define Props type explicitly
54
-
55
- **Environment Variables**
56
- - **Use build tool's environment variable system**: `process.env` does not work in browsers
57
- - **No secrets on client-side**: All frontend code is public, manage secrets in backend
58
-
59
- **Dependency Injection**
60
- - **Custom Hooks for dependency injection**: Ensure testability and modularity
61
-
62
- **Asynchronous Processing**
63
- - Promise Handling: Always use `async/await`
64
- - Error Handling: Always handle with `try-catch` or Error Boundary
65
- - Type Definition: Explicitly define return value types (e.g., `Promise<Result>`)
66
-
67
- **Format Rules**
68
- - Semicolon omission (follow Biome settings)
69
- - Types in `PascalCase`, variables/functions in `camelCase`
70
- - Imports use absolute paths (`src/`)
24
+ ```typescript
25
+ const raw: unknown = await (await fetch(url)).json()
26
+ if (!isUser(raw)) throw new ValidationError('invalid user')
27
+ const user = raw // narrowed to User
28
+ ```
71
29
 
72
- **Clean Code Principles**
73
- - Delete unused code immediately
74
- - Delete debug `console.log()`
75
- - No commented-out code (manage history with version control)
76
- - Comments explain "why" (not "what")
30
+ ## Component and State Design
31
+ - **Function components only.** Class components are allowed solely for Error Boundaries (no hook equivalent exists).
32
+ - **Type Props explicitly** with a named type and destructure: `function UserCard({ user, onSelect }: UserCardProps)`. Avoid `React.FC`; type props directly on the function so the props contract stays explicit.
33
+ - **Props-driven:** pass dependencies as props; reach into global state or Context only when needed.
34
+ - **Custom hooks** are the unit of logic reuse and dependency injection (inject collaborators through the hook for testability).
35
+ - **Function parameters:** 0-2 positional; for 3+ take a single options object.
36
+ - **State shape:** type state explicitly; for multi-field state with discrete transitions, use `useReducer` with a discriminated-union action type rather than many `useState` calls.
77
37
 
78
38
  ## Error Handling
39
+ - Surface every error: log and handle, or propagate — never swallow.
40
+ - **Fail fast:** on an invalid state, throw rather than returning a silent fallback.
41
+ - Represent expected failures as values with a `Result` type; reserve `throw` for unexpected/unrecoverable cases.
42
+ - Use purpose-specific error classes extending a base `AppError` carrying a `code` (e.g. ValidationError, ApiError, NotFoundError).
43
+ - **Layer responsibilities:** the API layer converts transport errors into domain errors; hooks propagate `AppError` upward; an Error Boundary catches render-time errors and shows fallback UI.
44
+ - Never log secrets (password, token, apiKey, creditCard).
79
45
 
80
- **Absolute Rule**: Error suppression prohibited. All errors must have log output and appropriate handling.
81
-
82
- **Fail-Fast Principle**: Fail quickly on errors to prevent continued processing in invalid states
83
- ```typescript
84
- // Prohibited: Unconditional fallback
85
- catch (error) {
86
- return defaultValue // Hides error
87
- }
88
-
89
- // Required: Explicit failure
90
- catch (error) {
91
- logger.error('Processing failed', error)
92
- throw error // Handle with Error Boundary or higher layer
93
- }
94
- ```
95
-
96
- **Result Type Pattern**: Express errors with types for explicit handling
97
46
  ```typescript
98
47
  type Result<T, E> = { ok: true; value: T } | { ok: false; error: E }
99
48
 
100
- // Example: Express error possibility with types
101
- function parseUser(data: unknown): Result<User, ValidationError> {
102
- if (!isValid(data)) return { ok: false, error: new ValidationError() }
103
- return { ok: true, value: data as User }
49
+ class AppError extends Error {
50
+ constructor(message: string, readonly code: string, readonly statusCode = 500) {
51
+ super(message); this.name = this.constructor.name
52
+ }
104
53
  }
105
54
  ```
106
55
 
107
- **Custom Error Classes**
56
+ Error Boundary — the one place a class component is required:
108
57
  ```typescript
109
- export class AppError extends Error {
110
- constructor(message: string, public readonly code: string, public readonly statusCode = 500) {
111
- super(message)
112
- this.name = this.constructor.name
113
- }
58
+ class ErrorBoundary extends React.Component<{ children: React.ReactNode; fallback: React.ReactNode }, { hasError: boolean }> {
59
+ state = { hasError: false }
60
+ static getDerivedStateFromError() { return { hasError: true } }
61
+ render() { return this.state.hasError ? this.props.fallback : this.props.children }
114
62
  }
115
- // Purpose-specific: ValidationError(400), ApiError(502), NotFoundError(404)
116
63
  ```
117
64
 
118
- **Layer-Specific Error Handling (React)**
119
- - Error Boundary: Catch React component errors, display fallback UI
120
- - Custom Hook: Detect business rule violations, propagate AppError as-is
121
- - API Layer: Convert fetch errors to domain errors
122
-
123
- **Structured Logging and Sensitive Information Protection**
124
- Never include sensitive information (password, token, apiKey, secret, creditCard) in logs
125
-
126
- **Asynchronous Error Handling in React**
127
- - Error Boundary setup mandatory: Catch rendering errors
128
- - Use try-catch with all async/await in event handlers
129
- - Always log and re-throw errors or display error state
130
-
131
- ## Performance Optimization
132
-
133
- - Component Memoization: Use React.memo for expensive components
134
- - State Optimization: Minimize re-renders with proper state structure
135
- - Lazy Loading: Use React.lazy and Suspense for code splitting
136
- - Bundle Size: Monitor with the `build` script and keep under 500KB
65
+ ## Project Conventions
66
+ - **Environment variables:** read through the build tool's env system (`process.env` is absent in the browser). Keep all secrets server-side — frontend code ships to the client.
67
+ - **Bundle & performance:** monitor with the `build` script, keep under 500KB; memoize expensive components (`React.memo`); code-split with `React.lazy` + `Suspense`; structure state to minimize re-renders.
68
+ - **Naming:** components/types `PascalCase`; variables/functions `camelCase`; hooks `use`-prefixed; constants `SCREAMING_SNAKE_CASE`.
69
+ - **Imports:** absolute paths from `src/`; order: React → external libs → internal (absolute) → internal (relative) → type-only → styles/assets.
70
+ - **Formatting:** follow Biome (semicolons and style come from project config).
@@ -140,8 +140,10 @@ describe('Button', () => {
140
140
 
141
141
  ## Test Design Patterns
142
142
 
143
+ Test user-visible results, not implementation details. Query by accessibility (`getByRole`/`getByLabelText`/`getByText`), not `getByTestId` or `container.querySelector`. Cover empty, error, and loading/async states, not only the happy path; await async UI with `findBy*`.
144
+
143
145
  ```typescript
144
- // Correct: test user-visible results
146
+ // Test the user-visible result
145
147
  it('increments count when clicked', async () => {
146
148
  const user = userEvent.setup()
147
149
  render(<Counter />)
@@ -149,10 +151,10 @@ it('increments count when clicked', async () => {
149
151
  expect(screen.getByText('Count: 1')).toBeInTheDocument()
150
152
  })
151
153
 
152
- // Avoid: testing implementation details
153
- it('calls setState', () => {
154
- const setState = vi.spyOn(React, 'useState')
155
- render(<Counter />)
156
- // ...
154
+ // Error state: override the handler for one test
155
+ it('shows an error message on API failure', async () => {
156
+ server.use(http.get('/api/users', () => new HttpResponse(null, { status: 500 })))
157
+ render(<UserList />)
158
+ expect(await screen.findByText('Something went wrong')).toBeInTheDocument()
157
159
  })
158
160
  ```
@@ -45,6 +45,8 @@ The two E2E lanes are budgeted independently — having a fixture-e2e for a jour
45
45
 
46
46
  ### Required Comment Format
47
47
 
48
+ The committed skeleton imports only the test framework (for `describe`/`it`/`it.todo`); the module under test is imported by the implementing task, never by the skeleton — a skeleton that references a not-yet-created module can fail gates that type-check, compile, or load test files before implementation begins.
49
+
48
50
  Each test MUST include the following annotations.
49
51
 
50
52
  ```typescript
@@ -216,14 +216,9 @@ According to scale determination:
216
216
 
217
217
  Note: At Small scale the implementation step still runs through task-executor with the standard 4-step cycle (`task-executor → escalation judgment → quality-fixer → commit`). Direct orchestrator edits are not used.
218
218
 
219
- ### Implementation Readiness Marker
219
+ ### Optional Preflight
220
220
 
221
- For Medium / Large scale, after Batch approval the work plan carries an `Implementation Readiness:` header (work-planner emits `pending`; promotion to `ready` or `escalated` is an external orchestration concern). The marker takes one of three values:
222
- - `pending` — initial state set by work-planner
223
- - `ready` — readiness verification has completed with no remaining gaps; safe to start the task execution cycle
224
- - `escalated` — readiness verification has completed but residual gaps require user judgment before execution
225
-
226
- External orchestration owns both the producer that promotes the marker beyond `pending` and the consumer that reads it before invoking task-executor. This guide does not invoke any orchestrator above the agent layer; agents read/write the marker only when explicitly asked.
221
+ For Medium / Large scale, after Batch approval implementation proceeds directly. Verifying the plan is implementable end-to-end (verification-strategy references, fixtures, UI rendering surface, E2E/local lane environment) is an optional preflight the user runs at their discretion via the prepare-implementation recipe, which exits no-op when readiness criteria already pass. This guide does not invoke any orchestrator above the agent layer.
227
222
 
228
223
  ## Cross-Layer Orchestration
229
224
 
@@ -192,21 +192,19 @@ skills:
192
192
  # Frontend-specific Skills
193
193
  frontend-typescript-rules:
194
194
  skill: "frontend-typescript-rules"
195
- tags: [frontend, react, implementation, type-safety, function-components, props-driven, async, refactoring, coding-style]
196
- typical-use: "React component creation, Props type definitions, frontend TypeScript development"
195
+ tags: [frontend, react, implementation, type-safety, component-design, props-driven, hooks, error-handling, conventions]
196
+ typical-use: "React component creation, Props/state design, error handling, frontend TypeScript implementation rules"
197
197
  size: small
198
198
  key-references:
199
- - "React Function Components - React Official"
200
- - "Props-driven Design - React Best Practices"
201
- - "YAGNI Principle - Kent Beck"
202
- - "Clean Code - Robert C. Martin"
203
- - "TypeScript satisfies Operator - Microsoft"
199
+ - "React Function Components - React docs"
200
+ - "Type guards at external boundaries (unknown narrowing)"
201
+ - "Result type and Error Boundary error handling"
204
202
  sections:
205
- - "Frontend-Specific Anti-patterns"
206
- - "Type Safety in Frontend Implementation"
207
- - "Coding Conventions"
203
+ - "Anti-patterns and Thresholds"
204
+ - "Type Safety at Boundaries"
205
+ - "Component and State Design"
208
206
  - "Error Handling"
209
- - "Performance Optimization"
207
+ - "Project Conventions"
210
208
 
211
209
  frontend-typescript-testing:
212
210
  skill: "frontend-typescript-testing"
@@ -5,8 +5,6 @@
5
5
  想定影響範囲: Xファイル
6
6
  関連Issue/PR: #XXX(該当する場合)
7
7
  レビュースコープ: [Design Docとタスク対象から導出した変更予定ファイルの範囲。既存作業に対する改訂計画の場合はベースブランチ + diff範囲]
8
- <!-- 下記の行はmedium / large規模のみ — small規模はこのplan-templateではなくtask-templateを使用する。値の行は末尾コメントを付けず、下流のパーサがbare statusの抽出(pending | ready | escalated)を行えるように保つこと。 -->
9
- Implementation Readiness: pending
10
8
 
11
9
  ## 関連ドキュメント
12
10
  - 設計書:
@@ -17,10 +17,10 @@ TypeScriptベースのReactアプリケーション実装。アーキテクチ
17
17
  - デフォルト値設定と必須チェックの適切な実装
18
18
 
19
19
  ```typescript
20
- // ビルドツールの環境変数(公開値のみ)
20
+ // ビルドツールの環境変数(公開値のみ。クライアント公開変数は VITE_ 接頭辞が必要)
21
21
  const config = {
22
- apiUrl: import.meta.env.API_URL || 'http://localhost:3000',
23
- appName: import.meta.env.APP_NAME || 'My App'
22
+ apiUrl: import.meta.env.VITE_API_URL || 'http://localhost:3000',
23
+ appName: import.meta.env.VITE_APP_NAME || 'My App'
24
24
  }
25
25
 
26
26
  // フロントエンドでは動作しない
@@ -5,311 +5,66 @@ description: React/TypeScriptの型安全性、コンポーネント設計、状
5
5
 
6
6
  # TypeScript 開発ルール(フロントエンド)
7
7
 
8
- ## 型システム
8
+ 実装向けの frontend 固有 React/TypeScript ルール: しきい値、境界での型安全性、コンポーネント/状態の設計、エラーハンドリング、プロジェクト規約。
9
9
 
10
- ### 型安全性の原則
11
- - **strictモード必須**: tsconfig.jsonでstrict: trueを設定
12
- - **any型使用禁止**: コードベースでany型を使用しない
13
- - **as使用最小化**: 型キャストはやむを得ない場合のみ(理由をコメント)
14
- - **unknown優先**: any型が必要な場合はunknown + 型ガード
10
+ ## アンチパターンとしきい値
11
+ 設計変更を促すシグナル:
12
+ - prop drilling が 3 階層以上 → Context または状態管理へ持ち上げる
13
+ - コンポーネントが 300 行超 → 分割する
14
+ - Props 10 個超 → コンポーネントを分割(3〜7 個が適正範囲)
15
+ - optional Props が 50% 超 → デフォルト値または Context を導入する
16
+ - Props のネストが 2 階層超 → フラット化する
17
+ - 同一の `as` アサーションが 3 回以上出現 → 型設計を見直す
15
18
 
16
- ```typescript
17
- // 良い: 型ガード付きのunknown
18
- function processData(data: unknown): User {
19
- if (!isUser(data)) throw new Error('Invalid user data')
20
- return data
21
- }
22
-
23
- // 悪い: any型の使用
24
- function processData(data: any): User {
25
- return data as User
26
- }
27
- ```
28
-
29
- ### 型定義のベストプラクティス
30
-
31
- #### オブジェクト型
32
- - **interface優先**: 拡張可能なオブジェクト型にはinterfaceを使用
33
- - **typeはunion/intersection用**: 複合型やユーティリティ型に使用
34
- - **readonlyの活用**: 不変なプロパティにはreadonlyを明示
35
-
36
- ```typescript
37
- // 良い: 明確な型定義
38
- interface User {
39
- readonly id: string
40
- name: string
41
- email: string
42
- }
43
-
44
- type UserWithRole = User & { role: 'admin' | 'user' }
45
- ```
46
-
47
- #### 関数型
48
- - **戻り値型を明示**: 複雑なロジックを持つ関数
49
- - **ジェネリクスの活用**: 再利用可能な型安全な関数
50
-
51
- ```typescript
52
- // 良い: 戻り値型を明示
53
- function calculateTotal(items: CartItem[]): number {
54
- return items.reduce((sum, item) => sum + item.price, 0)
55
- }
56
-
57
- // 良い: ジェネリクスの活用
58
- function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
59
- // implementation
60
- }
61
- ```
62
-
63
- ## Reactコンポーネント設計
64
-
65
- ### Function Components必須
66
-
67
- ```typescript
68
- // 良い: Function Component
69
- const UserCard: React.FC<UserCardProps> = ({ user, onSelect }) => {
70
- return (
71
- <div onClick={() => onSelect(user.id)}>
72
- {user.name}
73
- </div>
74
- )
75
- }
76
-
77
- // 悪い: Class Component(非推奨)
78
- class UserCard extends React.Component<UserCardProps> { }
79
- ```
19
+ ## 境界での型安全性
20
+ `any` を禁止する。型が得られない場合は `unknown` で受けて型ガードで絞り込む。`as` は最小化する(やむを得ない場合は理由をコメント)。
80
21
 
81
- ### Props型定義
22
+ アプリ内部では React の Props/State は型保証されており `unknown` は不要。外部境界では必ず `unknown` で受け、使用前に型ガードで絞り込む: API レスポンス、`localStorage`/`sessionStorage`、URL パラメータ、パースした JSON。制御コンポーネントのフォーム入力は React 合成イベントを通じて型安全に保たれる。
82
23
 
83
24
  ```typescript
84
- interface ButtonProps {
85
- label: string
86
- onClick: () => void
87
- variant?: 'primary' | 'secondary'
88
- disabled?: boolean
89
- }
90
-
91
- const Button: React.FC<ButtonProps> = ({
92
- label,
93
- onClick,
94
- variant = 'primary',
95
- disabled = false
96
- }) => {
97
- // implementation
98
- }
99
- ```
100
-
101
- ### Children Props
102
-
103
- ```typescript
104
- interface LayoutProps {
105
- children: React.ReactNode
106
- sidebar?: React.ReactNode
107
- }
108
-
109
- const Layout: React.FC<LayoutProps> = ({ children, sidebar }) => (
110
- <div>
111
- <main>{children}</main>
112
- {sidebar && <aside>{sidebar}</aside>}
113
- </div>
114
- )
115
- ```
116
-
117
- ## 状態管理
118
-
119
- ### useState型定義
120
-
121
- ```typescript
122
- // 良い: 明示的な型
123
- const [user, setUser] = useState<User | null>(null)
124
- const [items, setItems] = useState<Item[]>([])
125
-
126
- // 良い: 初期値から推論可能な場合
127
- const [count, setCount] = useState(0)
128
- ```
129
-
130
- ### useReducerの型安全性
131
-
132
- ```typescript
133
- type Action =
134
- | { type: 'SET_USER'; payload: User }
135
- | { type: 'CLEAR_USER' }
136
- | { type: 'SET_ERROR'; payload: string }
137
-
138
- interface State {
139
- user: User | null
140
- error: string | null
141
- }
142
-
143
- const reducer = (state: State, action: Action): State => {
144
- switch (action.type) {
145
- case 'SET_USER':
146
- return { ...state, user: action.payload, error: null }
147
- case 'CLEAR_USER':
148
- return { ...state, user: null }
149
- case 'SET_ERROR':
150
- return { ...state, error: action.payload }
151
- }
152
- }
25
+ const raw: unknown = await (await fetch(url)).json()
26
+ if (!isUser(raw)) throw new ValidationError('invalid user')
27
+ const user = raw // User に絞り込み済み
153
28
  ```
154
29
 
155
- ### Custom Hooks
156
-
157
- ```typescript
158
- interface UseUserReturn {
159
- user: User | null
160
- loading: boolean
161
- error: Error | null
162
- refetch: () => Promise<void>
163
- }
164
-
165
- function useUser(userId: string): UseUserReturn {
166
- const [user, setUser] = useState<User | null>(null)
167
- const [loading, setLoading] = useState(true)
168
- const [error, setError] = useState<Error | null>(null)
169
-
170
- const refetch = useCallback(async () => {
171
- setLoading(true)
172
- try {
173
- const data = await fetchUser(userId)
174
- setUser(data)
175
- } catch (e) {
176
- setError(e instanceof Error ? e : new Error('Unknown error'))
177
- } finally {
178
- setLoading(false)
179
- }
180
- }, [userId])
181
-
182
- useEffect(() => { refetch() }, [refetch])
183
-
184
- return { user, loading, error, refetch }
185
- }
186
- ```
30
+ ## コンポーネントと状態の設計
31
+ - **Function component のみ。** class component は Error Boundary に限り許可(hook の代替が存在しないため)。
32
+ - **Props は名前付き型で明示**し分割代入する: `function UserCard({ user, onSelect }: UserCardProps)`。`React.FC` は使わず、props を関数に直接型付けして Props 契約を明示する。
33
+ - **Props 駆動:** 依存は Props で渡す。グローバル状態や Context へは必要なときだけアクセスする。
34
+ - **Custom hook** をロジック再利用と依存注入の単位とする(テスト容易性のため、協調オブジェクトは hook 経由で注入する)。
35
+ - **関数引数:** 位置引数は 0〜2 個。3 個以上は単一の options オブジェクトで受ける。
36
+ - **状態の形:** 状態は明示的に型付けする。複数フィールドかつ離散的な遷移を持つ状態は、複数の `useState` ではなく discriminated union の action 型を用いた `useReducer` にする。
187
37
 
188
38
  ## エラーハンドリング
189
-
190
- ### Error Boundary
39
+ - すべてのエラーを表に出す: ログして処理するか伝播する — 握り潰さない。
40
+ - **Fail fast:** 不正な状態では、無言のフォールバックを返さず throw する。
41
+ - 想定内の失敗は `Result` 型で値として表現する。`throw` は想定外/回復不能なケースに限る。
42
+ - 目的別のエラークラスは `code` を持つ基底 `AppError` を継承する(例: ValidationError, ApiError, NotFoundError)。
43
+ - **層の責務:** API 層は transport エラーをドメインエラーへ変換する。hook は `AppError` を上位へ伝播する。Error Boundary はレンダリング時のエラーを捕捉しフォールバック UI を表示する。
44
+ - 機微情報(password, token, apiKey, creditCard)をログに出さない。
191
45
 
192
46
  ```typescript
193
- interface ErrorBoundaryProps {
194
- children: React.ReactNode
195
- fallback: React.ReactNode
196
- }
197
-
198
- interface ErrorBoundaryState {
199
- hasError: boolean
200
- }
47
+ type Result<T, E> = { ok: true; value: T } | { ok: false; error: E }
201
48
 
202
- class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
203
- state = { hasError: false }
204
-
205
- static getDerivedStateFromError(): ErrorBoundaryState {
206
- return { hasError: true }
207
- }
208
-
209
- render() {
210
- if (this.state.hasError) return this.props.fallback
211
- return this.props.children
49
+ class AppError extends Error {
50
+ constructor(message: string, readonly code: string, readonly statusCode = 500) {
51
+ super(message); this.name = this.constructor.name
212
52
  }
213
53
  }
214
54
  ```
215
55
 
216
- ### APIエラーハンドリング
217
-
56
+ Error Boundary — class component が必要となる唯一の箇所:
218
57
  ```typescript
219
- interface ApiError {
220
- code: string
221
- message: string
222
- details?: Record<string, string>
223
- }
224
-
225
- function isApiError(error: unknown): error is ApiError {
226
- return (
227
- typeof error === 'object' &&
228
- error !== null &&
229
- 'code' in error &&
230
- 'message' in error
231
- )
232
- }
233
-
234
- async function fetchWithErrorHandling<T>(url: string): Promise<T> {
235
- const response = await fetch(url)
236
-
237
- if (!response.ok) {
238
- const error: unknown = await response.json()
239
- if (isApiError(error)) {
240
- throw new ApiError(error.code, error.message)
241
- }
242
- throw new Error('Unknown API error')
243
- }
244
-
245
- return response.json() as Promise<T>
246
- }
247
- ```
248
-
249
- ## イベントハンドリング
250
-
251
- ### イベント型
252
-
253
- ```typescript
254
- const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
255
- e.preventDefault()
256
- // handle click
257
- }
258
-
259
- const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
260
- const value = e.target.value
261
- // handle change
262
- }
263
-
264
- const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
265
- e.preventDefault()
266
- // handle submit
58
+ class ErrorBoundary extends React.Component<{ children: React.ReactNode; fallback: React.ReactNode }, { hasError: boolean }> {
59
+ state = { hasError: false }
60
+ static getDerivedStateFromError() { return { hasError: true } }
61
+ render() { return this.state.hasError ? this.props.fallback : this.props.children }
267
62
  }
268
63
  ```
269
64
 
270
- ## コーディング規約
271
-
272
- ### 命名規則
273
- - **コンポーネント**: PascalCase(例: `UserProfile`)
274
- - **フック**: camelCase + use接頭辞(例: `useUserData`)
275
- - **型/インターフェース**: PascalCase(例: `UserProps`)
276
- - **定数**: SCREAMING_SNAKE_CASE(例: `MAX_RETRY_COUNT`)
277
- - **ファイル名**: コンポーネントはPascalCase、その他はcamelCase
278
-
279
- ### インポート順序
280
- 1. React関連
281
- 2. 外部ライブラリ
282
- 3. 内部モジュール(絶対パス)
283
- 4. 内部モジュール(相対パス)
284
- 5. 型のみのインポート
285
- 6. スタイル/アセット
286
-
287
- ```typescript
288
- import { useState, useEffect } from 'react'
289
- import { useQuery } from '@tanstack/react-query'
290
- import { api } from '@/lib/api'
291
- import { formatDate } from '../utils'
292
- import type { User } from '@/types'
293
- import styles from './Component.module.css'
294
- ```
295
-
296
- ## アンチパターン
297
-
298
- ### 避けるべきパターン
299
-
300
- ```typescript
301
- // 悪い: Propsのスプレッド展開
302
- const Button = (props: ButtonProps) => <button {...props} />
303
-
304
- // 良い: 明示的なPropsの受け渡し
305
- const Button = ({ label, onClick, disabled }: ButtonProps) => (
306
- <button onClick={onClick} disabled={disabled}>{label}</button>
307
- )
308
-
309
- // 悪い: インラインでの複雑なロジック
310
- {items.filter(i => i.active).map(i => <Item key={i.id} {...i} />)}
311
-
312
- // 良い: 事前に変数として抽出
313
- const activeItems = items.filter(item => item.active)
314
- {activeItems.map(item => <Item key={item.id} item={item} />)}
315
- ```
65
+ ## プロジェクト規約
66
+ - **環境変数:** ビルドツールの環境変数システム経由で読む(ブラウザに `process.env` は存在しない)。秘密情報はすべてサーバーサイドに置く — フロントエンドのコードはクライアントに配信される。
67
+ - **バンドルとパフォーマンス:** `build` スクリプトで監視し 500KB 未満に保つ。高コストなコンポーネントは `React.memo` でメモ化する。`React.lazy` + `Suspense` でコード分割する。再レンダリングを最小化する状態構造にする。
68
+ - **命名:** コンポーネント/型は `PascalCase`、変数/関数は `camelCase`、hook は `use` 接頭辞、定数は `SCREAMING_SNAKE_CASE`。
69
+ - **インポート:** `src/` からの絶対パス。順序: React → 外部ライブラリ → 内部(絶対)→ 内部(相対)→ 型のみ → スタイル/アセット。
70
+ - **フォーマット:** Biome に従う(セミコロンやスタイルはプロジェクト設定に従う)。