- 移除未使用的TabPane组件 - 修复类型定义和导入方式 - 优化mock数据源的环境变量判断逻辑 - 更新文档结构并归档旧文件 - 添加新的UI组件和Memo组件 - 调整API路径和响应处理
21 KiB
21 KiB
错误示例与正确示例对比(Wrong vs Right Examples)
模块: 05_AI - 错误示例与正确示例对比
更新日期: 2026-03-20
用途: 帮助 AI 快速识别错误代码模式并避免重复犯错
📋 使用说明
本文档通过对比错误示例和正确示例,帮助 AI:
- 快速识别错误模式
- 理解正确实现方式
- 避免重复犯错
- 提高代码质量
1️⃣ TypeScript 类型安全
1.1 禁止 any 类型
❌ 错误示例
// 错误:使用 any 类型
function handleData(data: any) {
return data.name
}
function processUser(user: any) {
console.log(user.email)
return user.id
}
const userData: any = fetchUser()
✅ 正确示例
// 正确:使用 unknown + 类型守卫
function handleData(data: unknown) {
if (typeof data === 'object' && data !== null && 'name' in data) {
return (data as { name: string }).name
}
throw new Error('Invalid data')
}
// 正确:使用类型守卫函数
function isUser(data: unknown): data is User {
return (
typeof data === 'object' &&
data !== null &&
'id' in data &&
'email' in data &&
typeof (data as User).id === 'string' &&
typeof (data as User).email === 'string'
)
}
function processUser(data: unknown) {
if (isUser(data)) {
console.log(data.email)
return data.id
}
throw new Error('Invalid user data')
}
// 正确:使用 Schema 验证
const userData = UserSchema.parse(fetchUser())
1.2 函数必须声明返回类型
❌ 错误示例
// 错误:未声明返回类型
function getUser(userId: string) {
return userRepository.findById(userId)
}
function calculateTotal(items: Item[]) {
return items.reduce((sum, item) => sum + item.price, 0)
}
async function fetchData(url: string) {
const response = await fetch(url)
return response.json()
}
✅ 正确示例
// 正确:声明返回类型
function getUser(userId: string): Promise<User | null> {
return userRepository.findById(userId)
}
function calculateTotal(items: Item[]): number {
return items.reduce((sum, item) => sum + item.price, 0)
}
async function fetchData<T>(url: string): Promise<T> {
const response = await fetch(url)
return response.json() as Promise<T>
}
1.3 API 必须定义类型
❌ 错误示例
// 错误:未定义类型
const response = await axios.get('/api/users')
const users = response.data
const createResponse = await axios.post('/api/users', userData)
const product = await fetch('/api/products/123').then(res => res.json())
✅ 正确示例
// 正确:定义请求和响应类型
interface ApiResponse<T> {
success: boolean
data: T
message?: string
}
interface User {
id: string
name: string
email: string
}
const response = await axios.get<ApiResponse<User[]>>('/api/users')
const users = response.data.data
const createResponse = await axios.post<ApiResponse<User>>('/api/users', userData)
const product = await fetch('/api/products/123')
.then(res => res.json() as Promise<ApiResponse<Product>>)
.then(data => data.data)
1.4 类型从 Schema 推导
❌ 错误示例
// 错误:手动定义类型
interface User {
id: string
name: string
email: string
age: number
}
interface Product {
id: string
name: string
price: number
}
// 错误:类型和 Schema 不一致
const UserSchema = z.object({
id: z.string(),
name: z.string(),
email: z.string().email()
// 缺少 age 字段
})
type User = z.infer<typeof UserSchema>
✅ 正确示例
// 正确:从 Schema 推导类型
import { z } from 'zod'
const UserSchema = z.object({
id: z.string().uuid(),
name: z.string().min(1).max(100),
email: z.string().email(),
age: z.number().int().positive()
})
type User = z.infer<typeof UserSchema>
const ProductSchema = z.object({
id: z.string().uuid(),
name: z.string().min(1).max(200),
price: z.number().positive()
})
type Product = z.infer<typeof ProductSchema>
1.5 统一类型中心
❌ 错误示例
// 错误:各模块重复定义类型
// dashboard/src/pages/User/User.tsx
interface User {
id: string
name: string
}
// server/src/models/User.ts
interface User {
id: string
name: string
email: string
}
// extension/src/types/User.ts
interface User {
id: string
name: string
email: string
role: string
}
✅ 正确示例
// 正确:从类型中心导入
// types/domain/User.ts
export const UserSchema = z.object({
id: z.string().uuid(),
name: z.string(),
email: z.string().email(),
role: z.enum(['ADMIN', 'MANAGER', 'OPERATOR'])
})
export type User = z.infer<typeof UserSchema>
// dashboard/src/pages/User/User.tsx
import { User } from '@/types/domain/User'
// server/src/models/User.ts
import { User } from '@/types/domain/User'
// node-agent/src/index.ts
import { User } from '@/types/domain/User'
2️⃣ 逻辑集中化
2.1 Controller 层职责
❌ 错误示例
// 错误:Controller 中写业务逻辑
export class UserController {
async createUser(req: Request, res: Response) {
const { username, email, password } = req.body
// 业务逻辑在 Controller 中
if (!username || !email || !password) {
return res.status(400).json({ error: 'Missing fields' })
}
if (password.length < 8) {
return res.status(400).json({ error: 'Password too short' })
}
const hashedPassword = await bcrypt.hash(password, 10)
const user = await this.userRepository.create({
username,
email,
passwordHash: hashedPassword,
role: 'OPERATOR',
status: 'ACTIVE'
})
res.json(user)
}
}
✅ 正确示例
// 正确:Controller 只负责请求/响应
export class UserController {
constructor(private readonly userService: UserService) {}
async createUser(req: Request, res: Response) {
try {
const userDTO = await this.userService.createUser(req.body)
res.json(createSuccessResponse(userDTO))
} catch (error) {
if (error instanceof ValidationError) {
res.status(400).json(createErrorResponse('VALIDATION_ERROR', error.message))
} else {
res.status(500).json(createErrorResponse('INTERNAL_ERROR', error.message))
}
}
}
}
// 业务逻辑在 Service 层
export class UserService {
async createUser(request: CreateUserRequest): Promise<UserDTO> {
// 1. 验证请求数据
const validatedRequest = CreateUserRequestSchema.parse(request)
// 2. 业务逻辑处理
const hashedPassword = await this.hashPassword(validatedRequest.password)
// 3. 创建领域模型
const user = UserSchema.parse({
id: crypto.randomUUID(),
username: validatedRequest.username,
email: validatedRequest.email,
passwordHash: hashedPassword,
role: validatedRequest.role || 'OPERATOR',
status: 'ACTIVE',
createdAt: new Date(),
updatedAt: new Date()
})
// 4. 保存到数据库
const savedUser = await this.userRepository.create(user)
// 5. 转换为 DTO
return toUserDTO(savedUser)
}
}
2.2 前端业务规则
❌ 错误示例
// 错误:前端直接写业务规则
function ProductCard({ product }: { product: Product }) {
// 业务规则在前端
const profitMargin = (product.price - product.cost) / product.price
// 业务判断在前端
const canSell = profitMargin >= 0.15
// 状态判断在前端
const statusText = product.status === 'ACTIVE' ? '可售' : '不可售'
return (
<div>
<h3>{product.name}</h3>
<p>利润率: {(profitMargin * 100).toFixed(2)}%</p>
<p>状态: {statusText}</p>
{canSell && <button>购买</button>}
</div>
)
}
✅ 正确示例
// 正确:前端只负责展示
function ProductCard({ product }: { product: ProductDTO }) {
return (
<div>
<h3>{product.name}</h3>
<p>利润率: {product.profitMargin}%</p>
<p>状态: {product.statusText}</p>
{product.canSell && <button onClick={() => handleBuy(product)}>购买</button>}
</div>
)
}
// 业务规则在 Service 层
export class ProductService {
async getProduct(id: string): Promise<ProductDTO> {
const product = await this.productRepository.findById(id)
if (!product) {
throw new NotFoundError('Product', id)
}
// 业务规则计算
const profitMargin = this.calculateProfitMargin(product)
const canSell = this.checkProfitMargin(profitMargin, product.businessType)
const statusText = this.getStatusText(product.status)
return {
...product,
profitMargin: (profitMargin * 100).toFixed(2),
canSell,
statusText
}
}
private calculateProfitMargin(product: Product): number {
return (product.price - product.cost) / product.price
}
private checkProfitMargin(margin: number, businessType: 'B2B' | 'B2C'): boolean {
const threshold = businessType === 'B2B' ? 0.15 : 0.20
return margin >= threshold
}
}
2.3 数据库操作
❌ 错误示例
// 错误:直接操作数据库
export class UserController {
async getUser(req: Request, res: Response) {
// 直接使用数据库连接
const user = await db('users').where({ id: req.params.id }).first()
res.json(user)
}
}
// 错误:跨模块直接操作数据库
export class OrderService {
async createOrder(orderData: OrderData) {
// 直接操作商品表
const product = await db('products').where({ id: orderData.productId }).first()
// 直接更新库存
await db('inventory').where({ product_id: orderData.productId }).decrement('quantity', orderData.quantity)
// 直接创建订单
const order = await db('orders').insert(orderData)
return order
}
}
✅ 正确示例
// 正确:通过 Repository 层操作数据库
export class UserController {
constructor(
private readonly userService: UserService
) {}
async getUser(req: Request, res: Response) {
const user = await this.userService.getUser(req.params.id)
res.json(createSuccessResponse(user))
}
}
// 正确:通过 Service 层协调多模块
export class OrderService {
constructor(
private readonly orderRepository: OrderRepository,
private readonly productService: ProductService,
private readonly inventoryService: InventoryService
) {}
async createOrder(orderData: OrderData): Promise<Order> {
// 通过 Service 获取商品信息
const product = await this.productService.getProduct(orderData.productId)
// 通过 Service 更新库存
await this.inventoryService.decreaseStock(orderData.productId, orderData.quantity)
// 通过 Repository 创建订单
const order = await this.orderRepository.create(orderData)
return order
}
}
3️⃣ 数据安全
3.1 表命名规范
❌ 错误示例
// 错误:表名不以 cf_ 开头
await db.schema.createTable('users', (table) => {
table.string('id').primary()
table.string('name')
table.string('email')
})
await db.schema.createTable('products', (table) => {
table.string('id').primary()
table.string('name')
table.decimal('price')
})
✅ 正确示例
// 正确:表名以 cf_ 开头
await db.schema.createTable('cf_users', (table) => {
table.string('id').primary()
table.string('name')
table.string('email')
})
await db.schema.createTable('cf_products', (table) => {
table.string('id').primary()
table.string('name')
table.decimal('price', 10, 2) // 金额字段使用 decimal(10,2)
})
3.2 金额字段
❌ 错误示例
// 错误:金额字段使用 float/double
await db.schema.createTable('cf_orders', (table) => {
table.string('id').primary()
table.float('total_amount') // 错误
table.double('subtotal') // 错误
})
// 错误:金额计算使用浮点数
const total = 10.5 + 20.3 // 30.800000000000004
const price = product.price * 1.1 // 浮点数精度问题
✅ 正确示例
// 正确:金额字段使用 decimal(10,2)
await db.schema.createTable('cf_orders', (table) => {
table.string('id').primary()
table.decimal('total_amount', 10, 2) // 正确
table.decimal('subtotal', 10, 2) // 正确
})
// 正确:金额计算使用整数(分)或 decimal
const total = Math.round((10.5 + 20.3) * 100) / 100 // 30.80
const price = Math.round(product.price * 1.1 * 100) / 100
// 或使用 decimal.js
import Decimal from 'decimal.js'
const total = new Decimal(10.5).plus(20.3).toNumber() // 30.8
3.3 五元组
❌ 错误示例
// 错误:缺少五元组
async function processOrder(orderId: string) {
const order = await orderRepository.findById(orderId)
await orderService.process(order)
}
// 错误:五元组不完整
const log = {
orderId: '123',
action: 'process',
timestamp: new Date()
}
✅ 正确示例
// 正确:包含完整五元组
interface TaskContext {
tenantId: string
shopId: string
taskId: string
traceId: string
businessType: 'TOC' | 'TOB'
}
async function processOrder(orderId: string, context: TaskContext) {
const order = await orderRepository.findById(orderId)
// 记录日志时包含五元组
logger.info('Processing order', {
...context,
orderId,
action: 'process'
})
await orderService.process(order, context)
}
// 正确:五元组完整
const log = {
tenantId: 'tenant-123',
shopId: 'shop-456',
taskId: 'task-789',
traceId: 'trace-abc',
businessType: 'TOC',
orderId: '123',
action: 'process',
timestamp: new Date()
}
4️⃣ 业务规则
4.1 状态机流转
❌ 错误示例
// 错误:非法状态流转
async function updateOrderStatus(orderId: string, newStatus: string) {
const order = await orderRepository.findById(orderId)
// 直接修改状态,未检查流转规则
order.status = newStatus
await orderRepository.update(orderId, order)
}
// 错误:跳过状态
async function shipOrder(orderId: string) {
const order = await orderRepository.findById(orderId)
// 从 PENDING 直接跳到 SHIPPED,跳过 PAID 和 PROCESSING
order.status = 'SHIPPED'
await orderRepository.update(orderId, order)
}
✅ 正确示例
// 正确:通过 Service 层遵循状态机
export class OrderService {
private readonly STATE_TRANSITIONS = {
PENDING: ['PAID', 'CANCELLED'],
PAID: ['PROCESSING', 'REFUNDED'],
PROCESSING: ['SHIPPED', 'REFUNDED'],
SHIPPED: ['COMPLETED', 'REFUNDED'],
COMPLETED: [],
CANCELLED: [],
REFUNDED: []
}
async updateOrderStatus(
orderId: string,
newStatus: OrderStatus,
context: TaskContext
): Promise<Order> {
const order = await this.orderRepository.findById(orderId)
if (!order) {
throw new NotFoundError('Order', orderId)
}
// 检查状态流转是否合法
if (!this.isValidTransition(order.status, newStatus)) {
throw new Error(`Invalid state transition: ${order.status} -> ${newStatus}`)
}
// 更新状态
order.status = newStatus
order.updatedAt = new Date()
const updatedOrder = await this.orderRepository.update(orderId, order)
// 记录状态变更日志
logger.info('Order status updated', {
...context,
orderId,
fromStatus: order.status,
toStatus: newStatus
})
return updatedOrder
}
private isValidTransition(from: OrderStatus, to: OrderStatus): boolean {
return this.STATE_TRANSITIONS[from]?.includes(to) || false
}
}
4.2 权限校验
❌ 错误示例
// 错误:硬编码权限判断
async function deleteUser(userId: string, req: Request) {
const user = req.user
// 硬编码权限判断
if (user.role !== 'ADMIN') {
throw new Error('Permission denied')
}
await userRepository.delete(userId)
}
// 错误:跳过权限校验
async function getAllUsers() {
return await userRepository.findAll()
}
✅ 正确示例
// 正确:使用 authorize 中间件
import { authorize } from '@/middleware/auth'
router.delete('/users/:id',
authorize('user:delete'),
userController.deleteUser
)
// 正确:Controller 中调用 Service
export class UserController {
async deleteUser(req: Request, res: Response) {
await this.userService.deleteUser(req.params.id)
res.json(createSuccessResponse({ message: 'User deleted' }))
}
}
// 正确:Service 层实现权限逻辑
export class UserService {
async deleteUser(userId: string): Promise<void> {
// 检查用户是否存在
const user = await this.userRepository.findById(userId)
if (!user) {
throw new NotFoundError('User', userId)
}
// 执行删除
await this.userRepository.delete(userId)
}
}
4.3 利润红线
❌ 错误示例
// 错误:未检查利润红线
async function createQuote(productId: string, price: number) {
const product = await productRepository.findById(productId)
// 未检查利润率
const quote = await quoteRepository.create({
productId,
price,
status: 'ACTIVE'
})
return quote
}
// 错误:仅用售价 - 采购价判断
const profit = price - product.cost
if (profit > 0) {
// 允许报价
}
✅ 正确示例
// 正确:使用 PricingService 检查利润红线
export class QuoteService {
constructor(
private readonly pricingService: PricingService,
private readonly quoteRepository: QuoteRepository
) {}
async createQuote(
productId: string,
price: number,
businessType: 'B2B' | 'B2C'
): Promise<Quote> {
const product = await this.productRepository.findById(productId)
if (!product) {
throw new NotFoundError('Product', productId)
}
// 计算净利率(含平台费/物流/税费/汇率/售后/广告摊销)
const profitMargin = await this.pricingService.calculateProfitMargin({
price,
cost: product.cost,
platform: product.platform,
businessType
})
// 检查利润红线
if (businessType === 'B2B' && profitMargin < 0.15) {
throw new Error('B2B profit margin must be at least 15%')
}
if (businessType === 'B2C' && profitMargin < 0.20) {
// 触发风控预警
await this.riskAlertService.createAlert({
type: 'LOW_PROFIT_MARGIN',
productId,
profitMargin,
threshold: 0.20
})
}
// 创建报价
const quote = await this.quoteRepository.create({
productId,
price,
profitMargin,
status: 'ACTIVE'
})
return quote
}
}
5️⃣ Mock 数据
5.1 硬编码 Mock 数据
❌ 错误示例
// 错误:在业务组件中硬编码 Mock 数据
function ProductList() {
const products = [
{ id: 1, name: 'Mock商品1', price: 100 },
{ id: 2, name: 'Mock商品2', price: 200 }
]
return (
<div>
{products.map(p => (
<div key={p.id}>{p.name}</div>
))}
</div>
)
}
// 错误:通过 if 判断切换 Mock/真实数据
async function getProducts() {
if (process.env.NODE_ENV === 'development') {
return mockProducts
}
return await api.getProducts()
}
✅ 正确示例
// 正确:通过 DataSource 抽象层
// services/productDataSource.ts
import { ProductDTOSchema, type ProductDTO } from '@/types'
export const productDataSource = {
async list(): Promise<ProductDTO[]> {
if (process.env.REACT_APP_USE_MOCK === 'true') {
const { mockProducts } = await import('@/mock/data/product.mock')
return mockProducts.map(p => ProductDTOSchema.parse(p))
}
const response = await api.getProducts()
return response.data.map(p => ProductDTOSchema.parse(p))
}
}
// components/ProductList.tsx
function ProductList() {
const { data: products } = useQuery({
queryKey: ['products'],
queryFn: () => productDataSource.list()
})
return (
<div>
{products?.map(p => (
<div key={p.id}>{p.name}</div>
))}
</div>
)
}
// mock/data/product.mock.ts
/**
* [MOCK] 商品 Mock 数据
* AI注意: 这是Mock实现,不是真实业务逻辑
* 仅在USE_MOCK=true时启用
*/
export const mockProducts = [
{ id: '1', name: '商品1', price: 100 },
{ id: '2', name: '商品2', price: 200 }
]
📊 总结
| 类别 | 常见错误 | 正确做法 |
|---|---|---|
| TypeScript | 使用 any、不声明返回类型 | 使用 unknown + 类型守卫、声明返回类型 |
| 逻辑集中化 | Controller 写业务逻辑 | 业务逻辑在 Service 层 |
| 数据安全 | 表名无前缀、金额用 float | 表名 cf_ 前缀、金额用 decimal(10,2) |
| 业务规则 | 非法状态流转、跳过权限校验 | 遵循状态机、使用 authorize 中间件 |
| Mock 数据 | 硬编码 Mock、if 判断切换 | DataSource 抽象层、环境变量控制 |
本文档持续更新,帮助 AI 避免常见错误。