--- paths: - "**/*.ts" - "**/*.tsx" - "**/*.js" - "**/*.jsx" --- # TypeScript / JavaScript ## Types and interfaces Use interface for object shapes that may be extended or implemented. Use type for unions, intersections, tuples, and utility types. Prefer string literal unions over enum unless interoperability requires it. interface User { id: string email: string } type UserRole = 'admin' | 'member' type UserWithRole = User & { role: UserRole } Add explicit parameter and return types to exported functions and public class methods. Let TypeScript infer obvious local variable types. ## Avoid any Never use any in application code. Use unknown for external or untrusted input, then narrow safely. Use generics when a value's type depends on the caller. // Wrong function getErrorMessage(error: any) { return error.message } // Correct function getErrorMessage(error: unknown): string { if (error instanceof Error) return error.message return 'Unexpected error' } ## React props Define component props with a named interface or type. Type callback props explicitly. Do not use React.FC unless there is a specific reason. interface UserCardProps { user: User onSelect: (id: string) => void } function UserCard({ user, onSelect }: UserCardProps) { return } ## Input validation with Zod Use Zod for schema-based validation and infer types from the schema. Do not duplicate type definitions — infer from the schema. import { z } from 'zod' const userSchema = z.object({ email: z.string().email(), age: z.number().int().min(0).max(150) }) type UserInput = z.infer const validated: UserInput = userSchema.parse(input) ## Error handling Use async/await with try-catch. Always narrow unknown errors before accessing properties. async function loadUser(userId: string): Promise { try { return await riskyOperation(userId) } catch (error: unknown) { logger.error('Operation failed', error) throw new Error(getErrorMessage(error)) } } ## console.log No console.log in production code. Use a proper logging library.