React/TypeScript frontend development rules including type safety, component design, state management, and error handling. Use when implementing React components, TypeScript code, or frontend features.
68
82%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Code first: names and types carry meaning; a comment must add what code cannot, and one comment per decision is enough. Frontend specifics:
Default Rule: Prefer unknown, generics, or union types over any. Retain any only when an existing external, generated, or legacy public signature requires it, or when replacing it prevents the project type check from expressing a safe generic relationship. Record the declaration path or type-check result that proves the constraint. When a local adapter can preserve compatibility and expose a safer type within the user request or current task/design artifact, implement the adapter; otherwise confine any to the smallest adapter or public-signature boundary, document the reason, and validate untrusted data before it enters typed application code.
any Type Alternatives (Priority Order)
Type Guard Implementation Pattern
function isUser(value: unknown): value is User {
return typeof value === 'object' && value !== null && 'id' in value && 'name' in value
}Modern Type Features
const config = { apiUrl: '/api' } satisfies Config - Preserves inferenceconst ROUTES = { HOME: '/' } as const satisfies Routes - Immutable and type-safetype UserId = string & { __brand: 'UserId' } - Distinguish meaningtype EventName = \on${Capitalize}`` - Express string patterns with typesType Safety in Frontend Implementation
unknown and validate at the boundary. A generated client may retain its declared type when it also enforces the contract at runtimestring | null at the browser boundary; treat parsed data as unknown until validatedstring | null shape, then parse and validate before converting to a domain typeType Safety in Data Flow
unknown) → Type Guard → State (Type Guaranteed)Type Complexity Review Signals
Use the following as prompts to review a design, not as pass/fail thresholds. Existing project conventions and a component's actual responsibility take precedence.
Component Design Criteria
Server/Client Boundary (RSC frameworks only — e.g., Next.js App Router)
"use client" boundary at the smallest scope that needs itwindow, localStorage, event handlers) inside client components; calling them in a server component breaks the renderState Management Patterns
useState for component-specific stateData Flow Principles
// Immutable state update — always create new arrays/objects
setUsers(prev => [...prev, newUser])Function Design
function createUser({ name, email, role }: CreateUserParams) {}Props Design (Props-driven Approach)
Environment Variables
import.meta.env, Next.js/CRA via prefixed process.env. Raw, unprefixed access is undefined in the browser bundleundefined in the browser. The prefix differs per tool — match the project's bundler (Vite VITE_, Next.js public NEXT_PUBLIC_, CRA REACT_APP_)// Vite example. Use the project's existing schema validator when one is configured.
const apiUrl = import.meta.env.VITE_API_URL
if (!apiUrl) {
throw new Error('Missing required client environment variable: VITE_API_URL')
}
const config = {
apiUrl,
appName: import.meta.env.VITE_APP_NAME ?? 'My App' // optional: intentional product default
}Security (Client-side Constraints)
.env files via .gitignore// Backend manages secrets, frontend accesses via proxy
const response = await fetch('/api/data') // Backend handles API key authenticationDependency Injection
Asynchronous Processing
async/await when it makes sequencing and error propagation clearertry-catch, a typed Result, or user-visible error state. Error Boundaries cover rendering failures in descendant components, not event handlers or ordinary asynchronous callbacksPromise<Result>); allow inference for local implementations when the contract remains clearuseEffect data fetches against out-of-order responses and post-unmount state updates — abort or ignore stale results (AbortController or a mounted flag), or use a server-state library (React Query/SWR) that cancels and dedupes. try-catch alone does not cover thisFormat Rules
PascalCase, variables/functions in camelCasesrc/ aliasClean Code Principles
console.log()Handling Rule: Every caught error must be intentionally propagated, converted to a typed error result, or represented as user-facing error state. Log it once at the boundary that owns diagnosis or recovery, with sensitive data redacted; avoid duplicate logging while propagating the same failure.
Fail-Fast Principle: Fail quickly on errors to prevent continued processing in invalid states
catch (error) {
logger.error('Processing failed', error)
throw error // Handle with Error Boundary or higher layer
}Result Type Pattern: Express errors with types for explicit handling
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E }
// Example: Express error possibility with types
function parseUser(data: unknown): Result<User, ValidationError> {
if (!isValid(data)) return { ok: false, error: new ValidationError() }
return { ok: true, value: data as User }
}Custom Error Classes
export class AppError extends Error {
constructor(message: string, public readonly code: string, public readonly statusCode = 500) {
super(message)
this.name = this.constructor.name
}
}
// Purpose-specific: ValidationError(400), ApiError(502), NotFoundError(404)Layer-Specific Error Handling (React)
Structured Logging and Sensitive Information Protection Redact sensitive fields (password, token, apiKey, secret, creditCard) before logging
Asynchronous Error Handling in React
try-catch, typed results, or rejected-promise propagation to the owning layerBasic Policy
Implementation Procedure: Understand Current State → Gradual Changes → Behavior Verification → Final Validation
Priority: Duplicate Code Removal > Large Function Division > Complex Conditional Branch Simplification > Type Safety Improvement
React.memo/useMemo/useCallback only as a profiler- or identity-justified escape hatch (a measured bottleneck, or stable reference identity for third-party APIs / effect dependencies)React.lazy and Suspense for code splitting56ab6c1
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.