typescript-rules
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTypeScript Development Rules (Frontend)
TypeScript前端开发规范
Basic Principles
基本原则
✅ Aggressive Refactoring - Prevent technical debt and maintain health
❌ Unused "Just in Case" Code - Violates YAGNI principle (Kent Beck)
✅ 积极重构 - 预防技术债务,保持代码健康
❌ 冗余的「以防万一」代码 - 违反YAGNI原则(Kent Beck提出)
Comment Writing Rules
注释编写规则
- Function Description Focus: Describe what the code "does"
- No Historical Information: Do not record development history
- Timeless: Write only content that remains valid whenever read
- Conciseness: Keep explanations to necessary minimum
- 聚焦函数描述:说明代码「做什么」
- 不记录历史信息:不要留存开发历史记录
- 时效性无关:仅编写任何时间阅读都有效的内容
- 简洁性:仅保留必要的解释内容
Type Safety
类型安全
Absolute Rule: any type is completely prohibited. It disables type checking and becomes a source of runtime errors.
any Type Alternatives (Priority Order)
- unknown Type + Type Guards: Use for validating external input (API responses, localStorage, URL parameters)
- Generics: When type flexibility is needed
- Union Types・Intersection Types: Combinations of multiple types
- Type Assertions (Last Resort): Only when type is certain
Type Guard Implementation Pattern
typescript
function isUser(value: unknown): value is User {
return typeof value === 'object' && value !== null && 'id' in value && 'name' in value
}Modern Type Features
- satisfies Operator: - Preserves inference
const config = { apiUrl: '/api' } satisfies Config - const Assertion: - Immutable and type-safe
const ROUTES = { HOME: '/' } as const satisfies Routes - Branded Types: - Distinguish meaning
type UserId = string & { __brand: 'UserId' } - Template Literal Types: on${Capitalize<string>}`` - Express string patterns with types
type EventName = \
Type Safety in Frontend Implementation
- React Props/State: TypeScript manages types, unknown unnecessary
- External API Responses: Always receive as , validate with type guards
unknown - localStorage/sessionStorage: Treat as , validate
unknown - URL Parameters: Treat as , validate
unknown - Form Input (Controlled Components): Type-safe with React synthetic events
Type Safety in Data Flow
- Frontend → Backend: Props/State (Type Guaranteed) → API Request (Serialization)
- Backend → Frontend: API Response () → Type Guard → State (Type Guaranteed)
unknown
Type Complexity Management
- Props Design:
- Props count: 3-7 props ideal (consider component splitting if exceeds 10)
- Optional Props: 50% or less (consider default values or Context if excessive)
- Nesting: Up to 2 levels (flatten deeper structures)
- Type Assertions: Review design if used 3+ times
- External API Types: Relax constraints and define according to reality (convert appropriately internally)
绝对规则:完全禁止使用any类型。它会禁用类型检查,成为运行时错误的源头。
any类型替代方案(优先级排序)
- unknown类型 + 类型守卫:用于验证外部输入(API响应、localStorage、URL参数)
- 泛型:需要类型灵活性时使用
- 联合类型・交叉类型:多种类型的组合
- 类型断言(最后手段):仅在确定类型时使用
类型守卫实现模式
typescript
function isUser(value: unknown): value is User {
return typeof value === 'object' && value !== null && 'id' in value && 'name' in value
}现代类型特性
- satisfies操作符:- 保留类型推断
const config = { apiUrl: '/api' } satisfies Config - const断言:- 不可变且类型安全
const ROUTES = { HOME: '/' } as const satisfies Routes - 品牌类型:- 区分类型含义
type UserId = string & { __brand: 'UserId' } - 模板字面量类型:on${Capitalize<string>}`` - 用类型表达字符串模式
type EventName = \
前端实现中的类型安全
- React Props/State:由TypeScript管理类型,无需使用unknown
- 外部API响应:始终以unknown类型接收,通过类型守卫验证
- localStorage/sessionStorage:视为unknown类型,进行验证
- URL参数:视为unknown类型,进行验证
- 表单输入(受控组件):通过React合成事件实现类型安全
数据流中的类型安全
- 前端 → 后端:Props/State(类型已保障)→ API请求(序列化)
- 后端 → 前端:API响应(unknown)→ 类型守卫 → State(类型已保障)
类型复杂度管理
- Props设计:
- Props数量:理想为3-7个(超过10个时考虑拆分组件)
- 可选Props:占比不超过50%(过多时考虑默认值或Context)
- 嵌套层级:最多2层(深层结构需扁平化)
- 类型断言:若使用超过3次,需重新审视设计
- 外部API类型:根据实际情况放宽约束并定义(内部按需转换)
Coding Conventions
编码规范
Component Design Criteria
- Function Components (Mandatory): Official React recommendation, optimizable by modern tooling
- Classes Prohibited: Class components completely deprecated (Exception: Error Boundary)
- Custom Hooks: Standard pattern for logic reuse and dependency injection
- Component Hierarchy: Atoms → Molecules → Organisms → Templates → Pages
- Co-location: Place tests, styles, and related files alongside components
State Management Patterns
- Local State: for component-specific state
useState - Context API: For sharing state across component tree (theme, auth, etc.)
- Custom Hooks: Encapsulate state logic and side effects
- Server State: React Query or SWR for API data caching
Data Flow Principles
- Single Source of Truth: Each piece of state has one authoritative source
- Unidirectional Flow: Data flows top-down via props
- Immutable Updates: Use immutable patterns for state updates
typescript
// ✅ Immutable state update
setUsers(prev => [...prev, newUser])
// ❌ Mutable state update
users.push(newUser)
setUsers(users)Function Design
- 0-2 parameters maximum: Use object for 3+ parameters
typescript
// ✅ Object parameter function createUser({ name, email, role }: CreateUserParams) {}
Props Design (Props-driven Approach)
- Props are the interface: Define all necessary information as props
- Avoid implicit dependencies: Do not depend on global state or context without necessity
- Type-safe: Always define Props type explicitly
Environment Variables
- Use build tool's environment variable system: does not work in browsers
process.env - Centrally manage environment variables through configuration layer
- Implement proper type safety and default value handling
typescript
// ✅ Build tool environment variables (public values only)
const config = {
apiUrl: import.meta.env.API_URL || 'http://localhost:3000',
appName: import.meta.env.APP_NAME || 'My App'
}
// ❌ Does not work in frontend
const apiUrl = process.env.API_URLSecurity (Client-side Constraints)
- CRITICAL: All frontend code is public and visible in browser
- Never store secrets client-side: No API keys, tokens, or secrets in environment variables
- Do not include files in Git
.env - Do not include sensitive information in error messages
typescript
// ❌ Security risk: API key exposed in browser
const apiKey = import.meta.env.API_KEY
const response = await fetch(`https://api.example.com/data?key=${apiKey}`)
// ✅ Correct: Backend manages secrets, frontend accesses via proxy
const response = await fetch('/api/data') // Backend handles API key authenticationDependency Injection
- Custom Hooks for dependency injection: Ensure testability and modularity
Asynchronous Processing
- Promise Handling: Always use
async/await - Error Handling: Always handle with or Error Boundary
try-catch - Type Definition: Explicitly define return value types (e.g., )
Promise<Result>
Format Rules
- Semicolon omission (follow Biome settings)
- Types in , variables/functions in
PascalCasecamelCase - Imports use absolute paths ()
src/
Clean Code Principles
- ✅ Delete unused code immediately
- ✅ Delete debug
console.log() - ❌ Commented-out code (manage history with version control)
- ✅ Comments explain "why" (not "what")
组件设计准则
- 必须使用函数式组件:React官方推荐,可通过现代工具优化
- 禁止使用类组件:类组件已完全弃用(例外:错误边界Error Boundary)
- 自定义Hooks:逻辑复用与依赖注入的标准模式
- 组件层级:原子组件 → 分子组件 → 组织组件 → 模板 → 页面
- 就近原则:将测试、样式及相关文件与组件放在同一目录
状态管理模式
- 局部状态:使用useState管理组件专属状态
- Context API:用于在组件树间共享状态(主题、权限等)
- 自定义Hooks:封装状态逻辑与副作用
- 服务端状态:使用React Query或SWR处理API数据缓存
数据流原则
- 单一数据源:每个状态仅存在一个权威来源
- 单向数据流:数据通过props自上而下传递
- 不可变更新:使用不可变模式更新状态
typescript
// ✅ 不可变状态更新
setUsers(prev => [...prev, newUser])
// ❌ 可变状态更新
users.push(newUser)
setUsers(users)函数设计
- 最多0-2个参数:参数超过3个时使用对象传递
typescript
// ✅ 对象参数 function createUser({ name, email, role }: CreateUserParams) {}
Props设计(Props驱动)
- Props即接口:将所有必要信息定义为Props
- 避免隐式依赖:非必要时不要依赖全局状态或Context
- 类型安全:始终显式定义Props类型
环境变量
- 使用构建工具的环境变量系统:process.env在浏览器中无法生效
- 通过配置层集中管理环境变量
- 实现适当的类型安全与默认值处理
typescript
// ✅ 构建工具环境变量(仅公开值)
const config = {
apiUrl: import.meta.env.API_URL || 'http://localhost:3000',
appName: import.meta.env.APP_NAME || 'My App'
}
// ❌ 前端环境下无法生效
const apiUrl = process.env.API_URL安全(客户端约束)
- 关键注意:所有前端代码都是公开的,可在浏览器中查看
- 绝不在客户端存储敏感信息:环境变量中不要包含API密钥、令牌或机密信息
- 不要将.env文件纳入Git版本控制
- 错误信息中不要包含敏感信息
typescript
// ❌ 安全风险:API密钥在浏览器中暴露
const apiKey = import.meta.env.API_KEY
const response = await fetch(`https://api.example.com/data?key=${apiKey}`)
// ✅ 正确做法:后端管理敏感信息,前端通过代理访问
const response = await fetch('/api/data') // 后端处理API密钥认证依赖注入
- 使用自定义Hooks实现依赖注入:确保可测试性与模块化
异步处理
- Promise处理:始终使用async/await
- 错误处理:始终通过try-catch或Error Boundary处理
- 类型定义:显式定义返回值类型(例如:)
Promise<Result>
格式规则
- 省略分号(遵循Biome配置)
- 类型使用PascalCase命名,变量/函数使用camelCase命名
- 导入使用绝对路径(开头)
src/
整洁代码原则
- ✅ 立即删除未使用的代码
- ✅ 删除调试用的
console.log() - ❌ 不要保留注释掉的代码(通过版本控制管理历史)
- ✅ 注释说明「为什么」(而非「做什么」)
Error Handling
错误处理
Absolute Rule: Error suppression prohibited. All errors must have log output and appropriate handling.
Fail-Fast Principle: Fail quickly on errors to prevent continued processing in invalid states
typescript
// ❌ Prohibited: Unconditional fallback
catch (error) {
return defaultValue // Hides error
}
// ✅ Required: Explicit failure
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
typescript
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
typescript
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)
- Error Boundary: Catch React component errors, display fallback UI
- Custom Hook: Detect business rule violations, propagate AppError as-is
- API Layer: Convert fetch errors to domain errors
Structured Logging and Sensitive Information Protection
Never include sensitive information (password, token, apiKey, secret, creditCard) in logs
Asynchronous Error Handling in React
- Error Boundary setup mandatory: Catch rendering errors
- Use try-catch with all async/await in event handlers
- Always log and re-throw errors or display error state
绝对规则:禁止抑制错误。所有错误必须记录日志并进行适当处理。
快速失败原则:遇到错误时立即终止,防止在无效状态下继续处理
typescript
// ❌ 禁止:无条件回退
catch (error) {
return defaultValue // 隐藏错误
}
// ✅ 必须:显式处理失败
catch (error) {
logger.error('处理失败', error)
throw error // 由Error Boundary或上层处理
}Result类型模式:通过类型表达错误,实现显式处理
typescript
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E }
// 示例:用类型表达错误可能性
function parseUser(data: unknown): Result<User, ValidationError> {
if (!isValid(data)) return { ok: false, error: new ValidationError() }
return { ok: true, value: data as User }
}自定义错误类
typescript
export class AppError extends Error {
constructor(message: string, public readonly code: string, public readonly statusCode = 500) {
super(message)
this.name = this.constructor.name
}
}
// 按用途细分:ValidationError(400), ApiError(502), NotFoundError(404)React分层错误处理
- Error Boundary:捕获React组件错误,显示回退UI
- 自定义Hooks:检测业务规则违规,直接传播AppError
- API层:将fetch错误转换为领域错误
结构化日志与敏感信息保护
日志中绝不能包含敏感信息(密码、令牌、apiKey、机密、信用卡信息)
React异步错误处理
- 必须设置Error Boundary:捕获渲染错误
- 事件处理中的所有async/await都要使用try-catch
- 始终记录日志并重新抛出错误,或显示错误状态
Refactoring Techniques
重构技巧
Basic Policy
- Small Steps: Maintain always-working state through gradual improvements
- Safe Changes: Minimize the scope of changes at once
- Behavior Guarantee: Ensure existing behavior remains unchanged while proceeding
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
基本策略
- 小步迭代:通过渐进式改进始终保持代码可运行
- 安全变更:每次最小化变更范围
- 行为保障:在重构过程中确保现有行为不变
实施流程:理解当前状态 → 渐进式变更 → 行为验证 → 最终确认
优先级:移除重复代码 > 拆分大函数 > 简化复杂条件分支 > 提升类型安全
Performance Optimization
性能优化
- Component Memoization: Use React.memo for expensive components
- State Optimization: Minimize re-renders with proper state structure
- Lazy Loading: Use React.lazy and Suspense for code splitting
- Bundle Size: Monitor with the script and keep under 500KB
build
- 组件记忆化:对性能开销大的组件使用React.memo
- 状态优化:通过合理的状态结构减少重渲染
- 懒加载:使用React.lazy和Suspense实现代码拆分
- 包体积:通过脚本监控,保持在500KB以内
build
Non-functional Requirements
非功能性需求
- Browser Compatibility: Chrome/Firefox/Safari/Edge (latest 2 versions)
- Rendering Time: Within 5 seconds for major pages
- 浏览器兼容性:Chrome/Firefox/Safari/Edge(最新2个版本)
- 渲染时间:主要页面加载时间控制在5秒以内