.claude/skills-ja/frontend-typescript-rules/SKILL.md
React/TypeScriptの型安全性、コンポーネント設計、状態管理ルールを適用。Reactコンポーネント実装時に使用。
npx skillsauth add shinpr/ai-coding-project-boilerplate frontend-typescript-rulesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
// 良い: 型ガード付きのunknown
function processData(data: unknown): User {
if (!isUser(data)) throw new Error('Invalid user data')
return data
}
// 悪い: any型の使用
function processData(data: any): User {
return data as User
}
// 良い: 明確な型定義
interface User {
readonly id: string
name: string
email: string
}
type UserWithRole = User & { role: 'admin' | 'user' }
// 良い: 戻り値型を明示
function calculateTotal(items: CartItem[]): number {
return items.reduce((sum, item) => sum + item.price, 0)
}
// 良い: ジェネリクスの活用
function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
// implementation
}
// 良い: Function Component
const UserCard: React.FC<UserCardProps> = ({ user, onSelect }) => {
return (
<div onClick={() => onSelect(user.id)}>
{user.name}
</div>
)
}
// 悪い: Class Component(非推奨)
class UserCard extends React.Component<UserCardProps> { }
interface ButtonProps {
label: string
onClick: () => void
variant?: 'primary' | 'secondary'
disabled?: boolean
}
const Button: React.FC<ButtonProps> = ({
label,
onClick,
variant = 'primary',
disabled = false
}) => {
// implementation
}
interface LayoutProps {
children: React.ReactNode
sidebar?: React.ReactNode
}
const Layout: React.FC<LayoutProps> = ({ children, sidebar }) => (
<div>
<main>{children}</main>
{sidebar && <aside>{sidebar}</aside>}
</div>
)
// 良い: 明示的な型
const [user, setUser] = useState<User | null>(null)
const [items, setItems] = useState<Item[]>([])
// 良い: 初期値から推論可能な場合
const [count, setCount] = useState(0)
type Action =
| { type: 'SET_USER'; payload: User }
| { type: 'CLEAR_USER' }
| { type: 'SET_ERROR'; payload: string }
interface State {
user: User | null
error: string | null
}
const reducer = (state: State, action: Action): State => {
switch (action.type) {
case 'SET_USER':
return { ...state, user: action.payload, error: null }
case 'CLEAR_USER':
return { ...state, user: null }
case 'SET_ERROR':
return { ...state, error: action.payload }
}
}
interface UseUserReturn {
user: User | null
loading: boolean
error: Error | null
refetch: () => Promise<void>
}
function useUser(userId: string): UseUserReturn {
const [user, setUser] = useState<User | null>(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState<Error | null>(null)
const refetch = useCallback(async () => {
setLoading(true)
try {
const data = await fetchUser(userId)
setUser(data)
} catch (e) {
setError(e instanceof Error ? e : new Error('Unknown error'))
} finally {
setLoading(false)
}
}, [userId])
useEffect(() => { refetch() }, [refetch])
return { user, loading, error, refetch }
}
interface ErrorBoundaryProps {
children: React.ReactNode
fallback: React.ReactNode
}
interface ErrorBoundaryState {
hasError: boolean
}
class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
state = { hasError: false }
static getDerivedStateFromError(): ErrorBoundaryState {
return { hasError: true }
}
render() {
if (this.state.hasError) return this.props.fallback
return this.props.children
}
}
interface ApiError {
code: string
message: string
details?: Record<string, string>
}
function isApiError(error: unknown): error is ApiError {
return (
typeof error === 'object' &&
error !== null &&
'code' in error &&
'message' in error
)
}
async function fetchWithErrorHandling<T>(url: string): Promise<T> {
const response = await fetch(url)
if (!response.ok) {
const error: unknown = await response.json()
if (isApiError(error)) {
throw new ApiError(error.code, error.message)
}
throw new Error('Unknown API error')
}
return response.json() as Promise<T>
}
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault()
// handle click
}
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value
// handle change
}
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
// handle submit
}
UserProfile)useUserData)UserProps)MAX_RETRY_COUNT)import { useState, useEffect } from 'react'
import { useQuery } from '@tanstack/react-query'
import { api } from '@/lib/api'
import { formatDate } from '../utils'
import type { User } from '@/types'
import styles from './Component.module.css'
// 悪い: Propsのスプレッド展開
const Button = (props: ButtonProps) => <button {...props} />
// 良い: 明示的なPropsの受け渡し
const Button = ({ label, onClick, disabled }: ButtonProps) => (
<button onClick={onClick} disabled={disabled}>{label}</button>
)
// 悪い: インラインでの複雑なロジック
{items.filter(i => i.active).map(i => <Item key={i.id} {...i} />)}
// 良い: 事前に変数として抽出
const activeItems = items.filter(item => item.active)
{activeItems.map(item => <Item key={item.id} item={item} />)}
development
Vitestテスト設計と品質基準を適用。カバレッジ要件とモック使用ガイドを提供。ユニットテスト作成時に使用。
development
型安全性とエラーハンドリングルールを適用。any禁止、型ガード必須。TypeScript実装、型定義レビュー時に使用。
tools
環境変数、アーキテクチャ設計、ビルド・テストコマンドを定義。環境設定、アーキテクチャ設計時に使用。
tools
タスクの本質を分析し適切なスキルを選択。規模見積もりとメタデータを返却。タスク開始時、スキル選択時に使用。