Install any skill in seconds. Free to start, no credit card required.
Get Started Free →当重构涉及字段映射(dataIndex、枚举映射、类型转换)时触发。防止字段名推测错误,确保字段映射的正确性。
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 30% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 62% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 27% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 97% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 47% | 0% |
<instructions>
不要根据类型定义推测字段名,必须查看原始代码的实际使用
场景:类型定义中有多个相似字段
typescriptinterface InvoiceHistory { changedAt?: string // 可选字段 createdAt: string // 必填字段 changeType?: string // 错误字段 operationType: string // 正确字段 }
错误做法:
typescript// ❌ 根据类型定义推测,选择了可选字段 dataIndex: 'changedAt' // 可能为 undefined → Invalid Date dataIndex: 'changeType' // 字段不存在 → 显示为空
正确做法:
typescript// ✅ 查看原始代码的实际使用 git show HEAD~1:src/components/InvoiceHistoryTab.tsx // 原始代码使用 createdAt(必填)和 operationType(正确) dataIndex: 'createdAt' dataIndex: 'operationType'
场景:重构时遗漏部分枚举值
错误做法:
typescript// ❌ 只保留了 3 个类型 typeMap: { CREATE: { text: '创建', color: 'green' }, UPDATE: { text: '更新', color: 'blue' }, DELETE: { text: '删除', color: 'red' }, }
正确做法:
typescript// ✅ 查看原始代码,确保完整 git show HEAD~1:src/components/InvoiceHistoryTab.tsx // 原始代码有 10 个类型 typeMap: { UPLOAD: { text: '上传发票', color: 'blue' }, OCR_START: { text: '开始OCR', color: 'cyan' }, OCR_SUCCESS: { text: 'OCR成功', color: 'green' }, OCR_FAILED: { text: 'OCR失败', color: 'red' }, OCR_RETRY: { text: '重试OCR', color: 'orange' }, MANUAL_EDIT: { text: '手动编辑', color: 'orange' }, LINK_ORDER: { text: '关联订单', color: 'purple' }, UNLINK_ORDER: { text: '取消关联', color: 'magenta' }, FIELD_CONFIRM: { text: '确认字段', color: 'green' }, DELETE: { text: '删除发票', color: 'red' }, }
场景:字段名错误但 TypeScript 不报错
typescript// ❌ TypeScript 不会报错(changedAt 在类型定义中存在) dataIndex: 'changedAt' // 类型检查通过 render: (val: string) => new Date(val).toLocaleString() // 运行时:val 为 undefined → Invalid Date
正确做法:
typescript// ✅ 运行时测试 + 防御性编程 dataIndex: 'createdAt' render: (val: string) => { if (!val) return '-' try { return new Date(val).toLocaleString('zh-CN') } catch { return val } }
场景:rowKey 使用了可能为 undefined 的字段
错误做法:
typescript// ❌ changedAt 可能为 undefined rowKey={(record, index) => `${record.changedAt}-${index}`} // 结果:undefined-0, undefined-1 → key 重复
正确做法:
typescript// ✅ 使用必填字段 id rowKey={(record) => record.id}
场景:从外部源(雷珏、ERP、CRM)定时/手动同步数据到本系统,每次同步都直接覆盖目标字段。
java// ❌ 源端这次没返回 categoryId,目标端 categoryId 被清成 null public void syncFromExternal(ExternalDetail detail) { Product product = productRepository.findById(detail.getProductId()).orElseThrow(); Long categoryId = resolveCategory(detail); // 可能返回 null product.setCategoryId(categoryId); // null 也覆盖 → 用户之前手动设置的分类被清空 productRepository.save(product); } // ✅ 源端缺失则不覆盖 public void syncFromExternal(ExternalDetail detail) { Product product = productRepository.findById(detail.getProductId()).orElseThrow(); Long categoryId = resolveCategory(detail); if (categoryId != null && !Objects.equals(product.getCategoryId(), categoryId)) { product.setCategoryId(categoryId); productRepository.save(product); } }
场景:用户在系统里把雷珏导入的商品分类从「家居」改到「办公用品」,下次雷珏导入又强制覆盖回「家居」→ 用户操作被悄悄丢弃。
伴随策略(last-sync-value pattern):在 mapping 表里记录"上次同步时给目标端的值",再覆盖前判断目标端是否仍等于该值。如果不等说明用户手动改过,跳过覆盖。
java// 1. mapping 表新增 last_category_id 字段 @Entity public class LeijueProductMapping { private Long productId; private Long lastCategoryId; // 上次同步时设置的 categoryId // ... } // 2. 同步时按"伴随策略"判定 private boolean syncCategoryField(Product product, Long newCategoryId, Long lastCategoryId) { if (newCategoryId == null) return false; // 源缺失不动(风险 5.1) boolean isInitial = product.getCategoryId() == null; boolean followingLastSync = Objects.equals(product.getCategoryId(), lastCategoryId); if (isInitial || followingLastSync) { product.setCategoryId(newCategoryId); return true; } else { log.info("跳过覆盖,目标已被人工调整: productId={}, current={}, lastSync={}, source={}", product.getId(), product.getCategoryId(), lastCategoryId, newCategoryId); return false; } } // 3. 同步成功后更新 lastCategoryId if (newCategoryId != null) { mapping.setLastCategoryId(newCategoryId); }
| 源端值 | 目标当前值 == lastSyncValue | 决策 | |--------|----------------------------|------| | null | 任意 | 不动(源缺失不清空) | | 有值 | true(仍是上次同步值) | 覆盖(用户未改过,跟随同步) | | 有值 | false(与上次不一致) | 跳过(用户改过,不要覆盖) | | 有值 | 目标为 null | 覆盖(首次同步) |
entity.setXxx(newValue) 前是否有 null 判断last_xxx 列log.info 便于排查bash# TypeScript 类型检查 npm run type-check # ESLint 检查 npm run lint
bash# 查看原始代码 git show HEAD~1:src/components/InvoiceHistoryTab.tsx # 制作对比清单 | 字段 | 原始代码 | 重构后 | 状态 | |------|---------|--------|------| | 时间字段 | createdAt | changedAt | ❌ 错误 | | 操作类型 | operationType | changeType | ❌ 错误 | | 枚举映射 | 10 个 | 3 个 | ❌ 不完整 | | rowKey | record.id | record.changedAt | ❌ 错误 |
typescript// ✅ 检查字段是否存在 render: (val: string) => { if (!val) return '-' return val }
typescript// ✅ 捕获异常 render: (val: string) => { if (!val) return '-' try { return new Date(val).toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false, }) } catch { return val } }
typescript// ✅ 提供默认值 render: (type: string) => { const config = typeMap[type] || { text: type, color: 'default' } return <Tag color={config.color}>{config.text}</Tag> }
> 📋 本回复遵循:`field-mapping-safety` - [章节]</instructions>
Other measured skills in the registry, with their headline benchmark lift.