AssetManager UniApp TypeScript 迁移计划
项目现状
| 类型 |
文件数 |
代码量 |
| Vue 页面 |
6 |
~3,768 行 |
| JS 工具 |
2 |
~350 行 |
| 配置文件 |
3 |
~100 行 |
迁移目标: JavaScript → TypeScript,获得类型安全 + IDE 智能提示
Phase 0:基础设施(0.5 天)
0.1 安装依赖
npm install -D typescript @types/node
npm install -D @uni-helper/vite-plugin-uni-types
0.2 配置文件
0.3 目录结构
src/
├── types/
│ ├── api.ts # API 响应类型
│ ├── portfolio.ts # 组合/持仓类型
│ ├── strategy.ts # 策略类型
│ └── global.d.ts # 全局类型声明
├── utils/
│ ├── api.ts # 迁移自 api.js
│ └── currency.ts # 迁移自 currency.js
└── pages/
└── ...
Phase 1:类型定义(1 天)
1.1 核心类型(与后端 DTO 对齐)
// types/portfolio.ts
export interface Portfolio {
id: string;
name: string;
currency: string;
strategyId?: string;
status: 'active' | 'archived';
totalValue: number;
totalCost: number;
returnRate: number;
createdAt: string;
updatedAt: string;
}
export interface Position {
id: string;
portfolioId: string;
stockCode: string;
stockName: string;
assetType: 'Stock' | 'Crypto' | 'Fund';
shares: number;
averageCost: number;
currentPrice: number;
marketValue: number;
profitLoss: number;
profitLossRate: number;
}
export interface Transaction {
id: string;
portfolioId: string;
type: 'buy' | 'sell' | 'dividend';
stockCode: string;
stockName: string;
shares: number;
price: number;
amount: number;
currency: string;
transactionAt: string;
}
// types/api.ts
export interface ApiResponse<T> {
code: number;
message: string;
data: T;
}
export interface AssetData {
totalValue: number;
todayProfit: number;
todayProfitCurrency: string;
totalReturnRate: number;
}
// types/strategy.ts
export interface Strategy {
id: string;
name: string;
type: 'RiskParity' | 'MaTrend' | 'ChandelierExit';
config: RiskParityConfig | MaTrendConfig | ChandelierExitConfig;
status: 'active' | 'paused';
}
export interface StrategySignal {
strategyType: string;
signal: 'BUY' | 'SELL' | 'HOLD' | 'REBALANCE';
reason: string;
positionSignals?: PositionSignal[];
generatedAt: string;
}
1.2 API 类型定义
Phase 2:工具函数迁移(0.5 天)
2.1 currency.js → currency.ts
// utils/currency.ts
export type CurrencyCode = 'CNY' | 'USD' | 'HKD' | 'EUR' | 'GBP' | 'JPY' | 'SGD' | 'AUD';
export function getCurrencySymbol(currency?: string): string { ... }
export function formatAmount(amount: number, currency?: CurrencyCode, decimals?: number): string { ... }
export function formatAmountWithSign(amount: number, currency?: CurrencyCode, decimals?: number): string { ... }
2.2 api.js → api.ts
2.3 迁移顺序
currency.js → currency.ts(简单,无依赖)
api.js → api.ts(依赖 Phase 1 的类型定义)
Phase 3:页面组件迁移(2-3 天)
迁移优先级
| 优先级 |
页面 |
行数 |
原因 |
| 1 |
me.vue |
259 |
最简单,练手 |
| 2 |
strategies/strategies.vue |
315 |
结构简单 |
| 3 |
strategies/edit/edit.vue |
997 |
表单,类型收益大 |
| 4 |
config/config.vue |
775 |
表单,类型收益大 |
| 5 |
detail/detail.vue |
1731 |
最复杂,逻辑最多 |
| 6 |
index/index.vue |
688 |
主页,依赖最多 |
迁移步骤(每个页面)
- 添加
lang="ts" 到 <script>
- 定义
interface 替代 data() 中的隐式类型
- Props 定义 →
defineProps<T>()
- Emits 定义 →
defineEmits<T>()
- 函数参数/返回值类型标注
- 修复类型错误
- 运行验证
3.1 示例:me.vue 迁移
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { api } from '@/utils/api';
import type { UserStats } from '@/types/user';
const loading = ref(true);
const userStats = ref<UserStats | null>(null);
onMounted(async () => {
try {
const res = await api.user.getUserStats();
userStats.value = res.data;
} finally {
loading.value = false;
}
});
</script>
Phase 4:清理与验证(0.5 天)
时间估算
| Phase |
内容 |
工时 |
| 0 |
基础设施 |
0.5 天 |
| 1 |
类型定义 |
1 天 |
| 2 |
工具函数 |
0.5 天 |
| 3 |
页面迁移 |
2-3 天 |
| 4 |
清理验证 |
0.5 天 |
| 总计 |
|
4-5 天 |
风险点
| 风险 |
缓解措施 |
| uview-plus 类型不全 |
遇到缺失时手写 .d.ts 补充 |
| uni-app API 类型 |
使用 @types/uni-app 或手写扩展 |
| 微信小程序兼容性 |
每个页面迁移后立即验证 |
| 后端 API 字段变更 |
类型定义与后端 DTO 保持同步 |
执行顺序建议
Day 1: Phase 0 + Phase 1(基础设施 + 类型定义)
Day 2: Phase 2 + Phase 3.1-3.2(工具函数 + 简单页面)
Day 3: Phase 3.3-3.4(中等复杂页面)
Day 4: Phase 3.5-3.6(复杂页面)
Day 5: Phase 4(清理验证 + buffer)
验收标准
创建时间:2026-03-24