12 KiB
12 KiB
开发规范
> 文档版本: v1.0.0 > 创建日期: 2026-05-25 > 适用范围: FischerX 项目开发人员
目录
代码规范
TypeScript 规范
类型定义
- 使用
type定义对象类型,使用interface定义类接口或需要扩展的类型 - 始终使用严格的类型检查,避免使用
any - 优先使用联合类型和字面量类型
// 好的做法
type User = {
id: string;
name: string;
email: string;
role: 'admin' | 'user' | 'guest';
};
interface Repository {
findById(id: string): Promise<User | null>;
save(user: User): Promise<User>;
}
// 避免
type User = any;
命名规范
- 类型名使用 PascalCase
- 常量使用 UPPER_SNAKE_CASE
- 变量和函数使用 camelCase
- 类使用 PascalCase
- React 组件使用 PascalCase
// 类型
type UserProfile = { ... };
// 常量
const MAX_RETRY_COUNT = 3;
const API_BASE_URL = 'https://api.example.com';
// 变量和函数
const userName = 'John';
function calculateTotal(price: number, quantity: number): number { ... }
// 类
class UserService { ... }
// React 组件
function UserProfileCard() { ... }
文件组织
- 一个文件一个主要导出
- 使用 index.ts 作为模块入口
- 按功能组织文件,而不是按类型
// 好的做法
user/
├── index.ts
├── types.ts
├── service.ts
├── repository.ts
└── hooks.ts
React/Next.js 规范
组件设计
- 使用函数组件,避免类组件
- 组件文件使用
.tsx扩展名 - 组件名与文件名保持一致
// components/UserCard.tsx
interface UserCardProps {
user: User;
onEdit?: (user: User) => void;
}
export function UserCard({ user, onEdit }: UserCardProps) {
return (
<div className="user-card">
<h3>{user.name}</h3>
<p>{user.email}</p>
{onEdit && <button onClick={() => onEdit(user)}>Edit</button>}
</div>
);
}
Hooks 规范
- 自定义 Hook 以
use开头 - Hook 应该只负责单一职责
- 使用 React Query 进行数据获取
- 使用 Zustand 进行状态管理
// hooks/useUser.ts
import { useQuery } from '@tanstack/react-query';
import { userApi } from '@/lib/api';
export function useUser(userId: string) {
return useQuery({
queryKey: ['user', userId],
queryFn: () => userApi.getById(userId),
enabled: !!userId,
});
}
表单处理
- 使用 React Hook Form
- 使用 Zod 进行验证
- 显示友好的错误信息
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import * as z from 'zod';
const formSchema = z.object({
name: z.string().min(2, 'Name too short'),
email: z.string().email('Invalid email'),
});
type FormValues = z.infer<typeof formSchema>;
function UserForm() {
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
});
const onSubmit = (data: FormValues) => {
console.log(data);
};
return <form onSubmit={form.handleSubmit(onSubmit)}>{/* ... */}</form>;
}
样式规范
- 使用 Tailwind CSS
- 组件内部样式放在
className中 - 复杂样式使用
clsx或tailwind-merge
import { clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
function cn(...inputs: any[]) {
return twMerge(clsx(inputs));
}
function Button({
children,
variant = 'primary',
className,
}: {
children: React.ReactNode;
variant?: 'primary' | 'secondary' | 'danger';
className?: string;
}) {
const variants = {
primary: 'bg-blue-600 text-white hover:bg-blue-700',
secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
danger: 'bg-red-600 text-white hover:bg-red-700',
};
return (
<button
className={cn(
'px-4 py-2 rounded font-medium transition-colors',
variants[variant],
className
)}
>
{children}
</button>
);
}
NestJS 规范
模块结构
- 按功能组织模块
- 每个模块包含 Controller、Service、Module
- 使用 Prisma 作为数据访问层
user/
├── user.module.ts
├── user.controller.ts
├── user.service.ts
├── dto/
│ ├── create-user.dto.ts
│ └── update-user.dto.ts
└── entities/
└── user.entity.ts
控制器规范
- Controller 只负责请求/响应处理
- 业务逻辑委托给 Service
- 使用 DTO 进行验证
- 使用 Swagger 装饰器生成文档
import { Controller, Get, Post, Body, Param, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
@ApiTags('users')
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Post()
@ApiOperation({ summary: 'Create user' })
@ApiResponse({ status: 201, description: 'User created' })
create(@Body() createUserDto: CreateUserDto) {
return this.userService.create(createUserDto);
}
@Get(':id')
@UseGuards(JwtAuthGuard)
@ApiOperation({ summary: 'Get user by ID' })
findOne(@Param('id') id: string) {
return this.userService.findOne(id);
}
}
服务规范
- Service 包含业务逻辑
- 使用依赖注入
- 抛出业务异常
import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { CreateUserDto } from './dto/create-user.dto';
import * as bcrypt from 'bcrypt';
@Injectable()
export class UserService {
constructor(private prisma: PrismaService) {}
async create(createUserDto: CreateUserDto) {
const hashedPassword = await bcrypt.hash(createUserDto.password, 10);
return this.prisma.user.create({
data: {
...createUserDto,
password: hashedPassword,
},
});
}
async findOne(id: string) {
const user = await this.prisma.user.findUnique({ where: { id } });
if (!user) {
throw new NotFoundException(`User with ID ${id} not found`);
}
return user;
}
}
DTO 规范
- 使用 class-validator 进行验证
- 使用 class-transformer 进行转换
- DTO 放在 dto 目录下
import { IsEmail, IsString, MinLength } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CreateUserDto {
@ApiProperty()
@IsString()
@MinLength(2)
name: string;
@ApiProperty()
@IsEmail()
email: string;
@ApiProperty()
@IsString()
@MinLength(8)
password: string;
}
Git 规范
分支策略
我们使用 Git Flow 工作流:
main (生产环境)
└── develop (开发环境)
├── feature/feature-name (功能分支)
├── bugfix/bug-name (修复分支)
├── hotfix/hotfix-name (紧急修复)
└── release/release-x.y.z (发布分支)
分支说明
| 分支类型 | 命名规范 | 说明 |
|---|---|---|
| main | main |
生产环境代码,始终稳定 |
| develop | develop |
开发环境代码,集成新功能 |
| feature | feature/xxx-yyy |
新功能开发 |
| bugfix | bugfix/xxx-yyy |
Bug 修复 |
| hotfix | hotfix/xxx-yyy |
生产环境紧急修复 |
| release | release/x.y.z |
发布准备 |
创建分支
# 从 develop 创建功能分支
git checkout develop
git pull origin develop
git checkout -b feature/user-authentication
# 从 main 创建紧急修复分支
git checkout main
git pull origin main
git checkout -b hotfix/critical-login-bug
提交规范
我们使用 Conventional Commits 规范:
<type>(<scope>): <subject>
<body>
<footer>
Type 类型
| 类型 | 说明 |
|---|---|
| feat | 新功能 |
| fix | Bug 修复 |
| docs | 文档更新 |
| style | 代码格式调整 |
| refactor | 重构 |
| perf | 性能优化 |
| test | 测试相关 |
| chore | 构建/工具相关 |
Scope 范围
web: Web 应用admin: 管理后台api: API 服务ui: UI 组件库core: 核心业务包types: 类型定义utils: 工具函数config: 配置
提交示例
# 新功能
git commit -m "feat(web): add user login page"
# Bug 修复
git commit -m "fix(api): handle null user in authentication"
# 文档更新
git commit -m "docs: update quick start guide"
# 重构
git commit -m "refactor(ui): restructure button component"
# 带正文的提交
git commit -m "feat(web): add password reset
- Add password reset form
- Add email verification
- Update API client
Closes #123"
PR 规范
PR 流程
- 创建分支并开发
- 提交代码
- 推送分支到远程
- 创建 Pull Request
- CI 检查
- 代码审查
- 修改(如果需要)
- 合并
PR 模板
## 描述
简要描述这个 PR 的改动。
## 类型
- [ ] feat (新功能)
- [ ] fix (Bug 修复)
- [ ] docs (文档更新)
- [ ] style (代码格式)
- [ ] refactor (重构)
- [ ] perf (性能优化)
- [ ] test (测试)
- [ ] chore (构建/工具)
## 改动范围
- [ ] apps/web
- [ ] apps/admin
- [ ] services/api
- [ ] packages/ui
- [ ] packages/core
- [ ] packages/types
- [ ] packages/utils
- [ ] 其他: ___
## 测试
- [ ] 单元测试已添加/更新
- [ ] 集成测试已添加/更新
- [ ] E2E 测试已添加/更新
- [ ] 手动测试已完成
## 截图(如果适用)
添加 UI 变化的截图。
## 相关 Issue
Closes #123, #456
## 检查清单
- [ ] 代码符合项目规范
- [ ] 已添加必要的测试
- [ ] 文档已更新
- [ ] CI 检查通过
代码审查清单
审查者应该检查以下内容:
功能正确性
- 代码实现了预期功能
- 边界情况已处理
- 错误处理正确
代码质量
- 代码清晰易读
- 命名有意义
- 没有重复代码
- 复杂度适中
性能
- 没有明显的性能问题
- 数据库查询优化
- 缓存使用合理
安全
- 输入已验证
- 没有 SQL 注入风险
- 敏感数据已保护
- 权限控制正确
测试
- 测试覆盖充分
- 测试可以通过
- 测试有意义
文档
- 代码注释充分
- API 文档已更新
- 使用文档已更新
合并策略
- Squash Merge: 功能分支合并到 develop,保持提交历史整洁
- Rebase Merge: 保持线性历史
- Merge Commit: 保留完整提交历史(用于 main 分支)
# Squash 合并示例
git checkout develop
git merge --squash feature/user-authentication
git commit -m "feat(web): add user authentication"
最佳实践提示
开发工作流
-
开始工作前
git checkout develop git pull origin develop -
创建分支
git checkout -b feature/your-feature-name -
定期提交
git add . git commit -m "feat: your commit message" -
推送到远程
git push -u origin feature/your-feature-name -
创建 PR
- 在 GitHub/GitLab 上创建 PR
- 填写 PR 模板
- 请求审查
-
更新分支
git checkout develop git pull origin develop git checkout feature/your-feature-name git rebase develop
避免常见错误
- ❌ 不要直接提交到 main 或 develop
- ❌ 不要提交大文件(使用 Git LFS)
- ❌ 不要提交敏感信息(API 密钥、密码等)
- ❌ 不要忽略测试失败
- ✅ 保持提交小而专注
- ✅ 写有意义的提交信息
- ✅ 及时更新文档
下一步
> 文档维护: 本文档由开发团队维护,如有问题或建议请提交 Issue。 > 最后更新: 2026-05-25