Skip to content

Instantly share code, notes, and snippets.

@anosatsuk124
Last active August 1, 2025 01:07
Show Gist options
  • Save anosatsuk124/8291e58aa3d1d9bec9f0ec579a340b47 to your computer and use it in GitHub Desktop.
Save anosatsuk124/8291e58aa3d1d9bec9f0ec579a340b47 to your computer and use it in GitHub Desktop.
Functional Claude for React/TS
<title>Strict Functional TypeScript/React Coding Standards</title>
<overview>
Based on CUPID (Composable, Unix philosophy, Predictable, Idiomatic, Domain-based) principles, express all logic as pure functions, control side effects explicitly, and maintain a type-safe, immutable codebase.
</overview>
<cupid>
<principle name="Composable">
Divide every piece of logic into pure functions and combine them only via compose or pipe patterns, enforcing single responsibility and explicit side-effect control.
</principle>
<principle name="Unix philosophy">
Ensure each module or file implements exactly one responsibility, executing side effects only at well-defined entry points.
</principle>
<principle name="Predictable">
Guarantee that the same input always produces the same output by separating internal state and external dependencies explicitly.
</principle>
<principle name="Idiomatic">
Leverage TypeScript and React’s standard APIs and language features fully, respecting their intended patterns and avoiding custom reimplementations.
</principle>
<principle name="Domain-based">
Reflect your domain model accurately in types and APIs, using branded or phantom types to define clear boundaries.
</principle>
</cupid>
<guidelines>
<item>Combine pure functions using compose or pipe patterns</item>
<item>Memoize curried and partially applied functions strictly with useCallback/useMemo</item>
<item>Implement data transformations as functional chains with map, filter, and reduce</item>
<item>Define all functions as arrow functions</item>
<item>Use explicit type declarations and leverage branded/phantom types to clarify boundaries</item>
<item>Build composable interfaces via intersection types</item>
<item>Express immutable data with readonly and allow mutable only when strictly necessary</item>
<item>Enforce exhaustive checks in switch statements using never types</item>
<item>Favor expressions over statements and minimize imperative code</item>
<item>Define strict enums using as const</item>
<item>Use named imports exclusively</item>
<item>Compose existing reusable pure functions; introduce utility functions only when reuse is guaranteed</item>
</guidelines>
<examples>
<example id="curry-and-memo">
<code>
import { useCallback, useMemo } from 'react'
type Add = (a: number) => (b: number) => number
const add: Add = a => b => a + b
export const useAdder = (a: number) => {
const curried = useMemo(() => add(a), [a])
const addB = useCallback((b: number) => curried(b), [curried])
return addB
}
</code>
</example>
<example id="reduce-sum">
<code>
export const sum = (numbers: readonly number[]): number =>
numbers.reduce((acc, x) => acc + x, 0)
</code>
</example>
<example id="branded-type">
<code>
declare const brand: unique symbol
type Branded<T, B> = T & { readonly [brand]: B }
export type UserId = Branded<number, 'UserId'>
export const createUserId = (n: number): UserId => n as UserId
</code>
</example>
<example id="pattern-matching">
<code>
export type Shape =
| { readonly kind: 'circle'; readonly radius: number }
| { readonly kind: 'square'; readonly side: number }
export const area = (shape: Shape): number => {
switch (shape.kind) {
case 'circle':
return Math.PI * shape.radius ** 2
case 'square':
return shape.side * shape.side
default:
const _exhaustiveCheck: never = shape
return _exhaustiveCheck
}
}
</code>
</example>
<example id="expression-style">
<code>
export const getStatusColor = (status: 'success' | 'error'): string =>
status === 'success' ? 'green' : 'red'
</code>
</example>
</examples>
<title>Strict Functional TypeScript/React コーディング規約</title>
<overview>
CUPID(Composable, Unix philosophy, Predictable, Idiomatic, Domain-based)原則を礎とし、
全てのロジックを純粋関数として表現し、副作用を明確に制御することで、
型安全かつイミュータブルなコードベースを維持することを目的とします。
</overview>
<cupid>
<principle name="Composable">
あらゆるロジックを純粋関数に分割し、compose/pipe パターンで組み合わせます。関数は単一責務を持ち、副作用は明示的に制御します。
</principle>
<principle name="Unix philosophy">
各モジュール/ファイルは単一責務の実装に専念し、副作用は明示的エントリポイントでのみ実行します。
</principle>
<principle name="Predictable">
同じ入力には必ず同じ出力を返す設計を徹底し、内部状態や外部依存は明示的に分離します。
</principle>
<principle name="Idiomatic">
TypeScript/React の標準APIと言語機能を最大限活用し、再実装や回避策を行いません。
</principle>
<principle name="Domain-based">
型とAPIはドメインモデルを忠実に反映し、branded/phantom type で境界を明示します。
</principle>
</cupid>
<guidelines>
<item>純粋関数を compose または pipe パターンで組み合わせる</item>
<item>useCallback/useMemo でカリー化と部分適用を厳密にメモ化する</item>
<item>map, filter, reduce でデータ変換を関数チェーンとして実装する</item>
<item>arrow function で全ての関数を定義する</item>
<item>明示的な型宣言と branded/phantom type で型の境界を明確化する</item>
<item>intersection 型を用いた composable な interface を定義する</item>
<item>immutable データは readonly で表現し、必要最小限の mutable のみ許可する</item>
<item>switch 文で exhaustive check を行い、never 型で型完全性を保証する</item>
<item>式を優先しステートメントを最小化する</item>
<item>as const で厳格な列挙型を定義する</item>
<item>named import を積極的に利用し、依存を明示する</item>
<item>再利用可能な純粋関数を組み合わせ、ユーティリティ関数は再利用性を担保したもののみ定義する</item>
</guidelines>
<examples>
<example id="curry-and-memo">
<code>
import { useCallback, useMemo } from 'react'
type Add = (a: number) => (b: number) => number
const add: Add = a => b => a + b
export const useAdder = (a: number) => {
const curried = useMemo(() => add(a), [a])
const addB = useCallback((b: number) => curried(b), [curried])
return addB
}
</code>
</example>
<example id="reduce-sum">
<code>
export const sum = (numbers: readonly number[]): number =>
numbers.reduce((acc, x) => acc + x, 0)
</code>
</example>
<example id="branded-type">
<code>
declare const brand: unique symbol
type Branded<T, B> = T & { readonly [brand]: B }
export type UserId = Branded<number, 'UserId'>
export const createUserId = (n: number): UserId => n as UserId
</code>
</example>
<example id="pattern-matching">
<code>
export type Shape =
| { readonly kind: 'circle'; readonly radius: number }
| { readonly kind: 'square'; readonly side: number }
export const area = (shape: Shape): number => {
switch (shape.kind) {
case 'circle':
return Math.PI * shape.radius ** 2
case 'square':
return shape.side * shape.side
default:
const _exhaustiveCheck: never = shape
return _exhaustiveCheck
}
}
</code>
</example>
<example id="expression-style">
<code>
export const getStatusColor = (status: 'success' | 'error'): string =>
status === 'success' ? 'green' : 'red'
</code>
</example>
</examples>

ChatGPT o4-mini-high(2025-08-01時点) で作成。

ルール生成元プロンプト:

関数型プログラミングをTypeScript+Reactで実現するためのCLAUDE.mdファイル作成。URLについてはあなたが事前に読んで要約してください。また本質的なコードスニペットを示すようにしてください。
  
- カリー化を使用し、適切に部分適用したものをuseCallback/useMemoなどで適切にメモ化することでの効率的な使用。
- reduceやmapやfilterなどを積極的に使う。
- ifはnestしない。
- arrow関数を使用し、function宣言は避ける。
- 明示的な型宣言。生のJS型を極力避けつつ、newなどのobjectの生成も避け(効率のため)、型システムを活用する。
- composableなinterface定義。&を使ったintersectionを用い、複数のinterfaceを組み合わせて、理解しやすい表現にする。
- mutableなデータ構造とimmutableなデータ構造の区別。
- never型を用いたpattern matching(switch statementでのexhaustive check)
- 文より式を優先。
- ユニットテストしやすい単位で、関数/コンポーネント/hooksを作成する。
- 可能な場合は常にreadonlyを使う
- enumを避け、as constを使って列挙型を作成する。
- branded typeやphantom typeなどを用いた型の区別
    - https://scrapbox.io/mrsekut-p/branded_types などを参考に
- また、SOLID原則はさほど重視せず、CUPID原則を意識すること
    - https://dannorth.net/blog/cupid-for-joyful-coding/ CUPID原則についてはこれを参照
- 説明的で自明なコメントは禁止。できる限り、コードから意図を読み取れるようにする。
- importはnamed importを使用し、default importは避ける。
- これらを遂行するためだけの無駄なutility関数は決して作らない。

他、いくつかの追加の指示を含むため、会話の履歴を参照: https://chatgpt.com/share/688c10c1-abc8-8008-87b9-d3e856d86f30

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment