react-dev
TypeScriptを使ったReactコンポーネントの構築、フックの型付け、イベント処理、またはReact TypeScript・React 19・Server Componentsに関する作業を行う際に使用するスキルです。ジェネリックコンポーネント、適切なイベント型付け、ルーティング連携(TanStack Router・React Router)など、React 18〜19における型安全なパターンを網羅しています。
description の原文を見る
This skill should be used when building React components with TypeScript, typing hooks, handling events, or when React TypeScript, React 19, Server Components are mentioned. Covers type-safe patterns for React 18-19 including generic components, proper event typing, and routing integration (TanStack Router, React Router).
SKILL.md 本文
React TypeScript
型安全な React = コンパイル時保証 = 自信を持ったリファクタリング。
<when_to_use>
- 型付き React コンポーネントの構築
- ジェネリックコンポーネントの実装
- イベントハンドラー、フォーム、ref の型付け
- React 19 機能の使用(Actions、Server Components、use())
- ルーター統合(TanStack Router、React Router)
- 適切な型付けを備えたカスタムフック
NOT for: React 以外の TypeScript、バニラ JS React
</when_to_use>
<react_19_changes>
React 19 の破壊的変更には移行が必要です。主なパターン:
ref as prop - forwardRef 非推奨:
// React 19 - ref を通常の prop として
type ButtonProps = {
ref?: React.Ref<HTMLButtonElement>;
} & React.ComponentPropsWithoutRef<'button'>;
function Button({ ref, children, ...props }: ButtonProps) {
return <button ref={ref} {...props}>{children}</button>;
}
useActionState - useFormState の代わり:
import { useActionState } from 'react';
type FormState = { errors?: string[]; success?: boolean };
function Form() {
const [state, formAction, isPending] = useActionState(submitAction, {});
return <form action={formAction}>...</form>;
}
use() - Promise とコンテキストをアンラップ:
function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
const user = use(userPromise); // 解決まで Suspend
return <div>{user.name}</div>;
}
詳細は react-19-patterns.md を参照。useOptimistic、useTransition、移行チェックリストを含みます。
</react_19_changes>
<component_patterns>
Props - ネイティブ要素を拡張:
type ButtonProps = {
variant: 'primary' | 'secondary';
} & React.ComponentPropsWithoutRef<'button'>;
function Button({ variant, children, ...props }: ButtonProps) {
return <button className={variant} {...props}>{children}</button>;
}
Children 型付け:
type Props = {
children: React.ReactNode; // レンダリング可能なもの
icon: React.ReactElement; // 単一要素
render: (data: T) => React.ReactNode; // Render prop
};
Discriminated unions - バリアント prop 用:
type ButtonProps =
| { variant: 'link'; href: string }
| { variant: 'button'; onClick: () => void };
function Button(props: ButtonProps) {
if (props.variant === 'link') {
return <a href={props.href}>Link</a>;
}
return <button onClick={props.onClick}>Button</button>;
}
</component_patterns>
<event_handlers>
ターゲット型を正確にするために、特定のイベント型を使用:
// Mouse
function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
e.currentTarget.disabled = true;
}
// Form
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
const formData = new FormData(e.currentTarget);
}
// Input
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
console.log(e.target.value);
}
// Keyboard
function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
if (e.key === 'Enter') e.currentTarget.blur();
}
詳細は event-handlers.md を参照。フォーカス、ドラッグ、クリップボード、タッチ、ホイールイベントを含みます。
</event_handlers>
<hooks_typing>
useState - 合併型・null に対して明示的:
const [user, setUser] = useState<User | null>(null);
const [status, setStatus] = useState<'idle' | 'loading'>('idle');
useRef - DOM は null、可変は値:
const inputRef = useRef<HTMLInputElement>(null); // DOM - ?. を使用
const countRef = useRef<number>(0); // 可変 - 直接アクセス
useReducer - アクション用 discriminated union:
type Action =
| { type: 'increment' }
| { type: 'set'; payload: number };
function reducer(state: State, action: Action): State {
switch (action.type) {
case 'set': return { ...state, count: action.payload };
default: return state;
}
}
Custom hooks - as const による tuple 戻り値:
function useToggle(initial = false) {
const [value, setValue] = useState(initial);
const toggle = () => setValue(v => !v);
return [value, toggle] as const;
}
useContext - null ガードパターン:
const UserContext = createContext<User | null>(null);
function useUser() {
const user = useContext(UserContext);
if (!user) throw new Error('useUser outside UserProvider');
return user;
}
詳細は hooks.md を参照。useCallback、useMemo、useImperativeHandle、useSyncExternalStore を含みます。
</hooks_typing>
<generic_components>
ジェネリックコンポーネントは prop から型を推論 - 呼び出しサイトでの手動アノテーション不要。
パターン - keyof T で列キー、render prop でカスタムレンダリング:
type Column<T> = {
key: keyof T;
header: string;
render?: (value: T[keyof T], item: T) => React.ReactNode;
};
type TableProps<T> = {
data: T[];
columns: Column<T>[];
keyExtractor: (item: T) => string | number;
};
function Table<T>({ data, columns, keyExtractor }: TableProps<T>) {
return (
<table>
<thead>
<tr>{columns.map(col => <th key={String(col.key)}>{col.header}</th>)}</tr>
</thead>
<tbody>
{data.map(item => (
<tr key={keyExtractor(item)}>
{columns.map(col => (
<td key={String(col.key)}>
{col.render ? col.render(item[col.key], item) : String(item[col.key])}
</td>
))}
</tr>
))}
</tbody>
</table>
);
}
制約付きジェネリクス - 必須プロパティ用:
type HasId = { id: string | number };
function List<T extends HasId>({ items }: { items: T[] }) {
return <ul>{items.map(item => <li key={item.id}>...</li>)}</ul>;
}
詳細は generic-components.md を参照。Select、List、Modal、FormField パターンを含みます。
</generic_components>
<server_components>
React 19 Server Components はサーバー上で実行され、非同期にできます。
非同期データ取得:
export default async function UserPage({ params }: { params: { id: string } }) {
const user = await fetchUser(params.id);
return <div>{user.name}</div>;
}
Server Actions - ミューテーション用 'use server':
'use server';
export async function updateUser(userId: string, formData: FormData) {
await db.user.update({ where: { id: userId }, data: { ... } });
revalidatePath(`/users/${userId}`);
}
Client + Server Action:
'use client';
import { useActionState } from 'react';
import { updateUser } from '@/actions/user';
function UserForm({ userId }: { userId: string }) {
const [state, formAction, isPending] = useActionState(
(prev, formData) => updateUser(userId, formData), {}
);
return <form action={formAction}>...</form>;
}
Promise ハンドオフ用 use():
// Server: await なしで promise をパス
async function Page() {
const userPromise = fetchUser('123');
return <UserProfile userPromise={userPromise} />;
}
// Client: use() でアンラップ
'use client';
function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
const user = use(userPromise);
return <div>{user.name}</div>;
}
詳細は server-components.md を参照。並列取得、ストリーミング、エラーバウンダリーを含みます。
</server_components>
<routing>TanStack Router と React Router v7 の両方が型安全なルーティングソリューションを提供します。
TanStack Router - Zod 検証による実行時型安全性:
import { createRoute } from '@tanstack/react-router';
import { z } from 'zod';
const userRoute = createRoute({
path: '/users/$userId',
component: UserPage,
loader: async ({ params }) => ({ user: await fetchUser(params.userId) }),
validateSearch: z.object({
tab: z.enum(['profile', 'settings']).optional(),
page: z.number().int().positive().default(1),
}),
});
function UserPage() {
const { user } = useLoaderData({ from: userRoute.id });
const { tab, page } = useSearch({ from: userRoute.id });
const { userId } = useParams({ from: userRoute.id });
}
React Router v7 - Framework Mode での自動型生成:
import type { Route } from "./+types/user";
export async function loader({ params }: Route.LoaderArgs) {
return { user: await fetchUser(params.userId) };
}
export default function UserPage({ loaderData }: Route.ComponentProps) {
const { user } = loaderData; // loader から型付け
return <h1>{user.name}</h1>;
}
詳細は tanstack-router.md を参照(TanStack パターン)と react-router.md を参照(React Router パターン)。
常に(ALWAYS):
- 特定のイベント型(MouseEvent、ChangeEvent など)
- 合併型・null に対して明示的な useState
- ネイティブ要素拡張に ComponentPropsWithoutRef
- バリアント prop に discriminated union
- tuple 戻り値に as const
- React 19 での ref as prop(forwardRef なし)
- フォームアクションに useActionState
- 型安全なルーティングパターン(ルーティングセクション参照)
決してしない(NEVER):
- イベントハンドラーに any
- children に JSX.Element(ReactNode を使用)
- React 19+ での forwardRef
- useFormState(非推奨)
- DOM ref の null 処理を忘れる
- 同じファイルで Server/Client コンポーネントを混在
- use() に渡す promise を await する
hooks.md- useState、useRef、useReducer、useContext、カスタムフックevent-handlers.md- すべてのイベント型、ジェネリックハンドラーreact-19-patterns.md- useActionState、use()、useOptimistic、移行generic-components.md- Table、Select、List、Modal パターンserver-components.md- 非同期コンポーネント、Server Actions、ストリーミングtanstack-router.md- TanStack Router 型付きルート、サーチパラム、ナビゲーションreact-router.md- React Router v7 ローダー、アクション、型生成、フォーム
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- softaworks
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/softaworks/agent-toolkit / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。