代码规范
概述
本文档定义了 HCompass 项目的代码规范,所有开发者都应遵循这些规范,以确保代码的一致性和可维护性。
核心技术栈约束
开发平台
- HarmonyOS:使用 ArkTS/TypeScript 开发
- API 版本:优先使用官方最新稳定版 API
状态管理
- 强制使用 V2 版本:@ObservedV2 / AppStorageV2 / PersistenceV2
- 禁用 V1 版本:禁止使用所有 V1 版本的状态管理 API
架构模式
- MVVM 架构:严格遵循 MVVM 多模块架构
- View 层职责:仅负责渲染,不包含业务逻辑
- ViewModel 职责:封装所有业务逻辑
组件优先级
- 模块内复用组件
- core/components 跨模块通用组件
- IBest-UI-V2 组件库
- 禁止重复开发已有组件
代码风格
命名规范
变量和函数
使用 camelCase(小驼峰)命名:
typescript
// 好的命名
const userName: string = "张三";
const userAge: number = 25;
function getUserInfo(): UserInfo {
// ...
}
function handleButtonClick(): void {
// ...
}类和接口
使用 PascalCase(大驼峰)命名:
typescript
// 类
export class UserViewModel {
// ...
}
// 接口
export interface IUserService {
// ...
}
// 类型
export interface UserInfo {
// ...
}常量
使用 UPPER_SNAKE_CASE(大写蛇形)命名:
typescript
export const MAX_PAGE_SIZE: number = 100;
export const COLOR_PRIMARY: string = "#007AFF";
export const API_BASE_URL: string = "https://api.example.com";代码格式
字符串
默认使用双引号:
typescript
// 推荐
const message: string = "Hello, World!";
// 不推荐
const message: string = 'Hello, World!';语句结尾
必须加分号:
typescript
// 推荐
const name: string = "张三";
const age: number = 25;
// 不推荐
const name: string = "张三"
const age: number = 25变量声明
- 禁用
var - 优先使用
const - 其次使用
let
typescript
// 推荐
const PI: number = 3.14;
let count: number = 0;
// 不推荐
var count: number = 0;类型注解
禁用 any 类型
所有方法、参数、返回值必须编写完整类型注解:
typescript
// 推荐
function getUserInfo(userId: string): Promise<UserInfo> {
// ...
}
// 不推荐
function getUserInfo(userId: any): Promise<any> {
// ...
}接口和类型
接口和类型需显式声明:
typescript
// 推荐
export interface UserInfo {
id: string;
username: string;
email: string;
}
export type UserRole = "admin" | "user" | "guest";
// 不推荐
export const userInfo = {
id: "123",
username: "张三",
email: "zhangsan@example.com"
};注释规范
文件头注释
文件头部必须包含 @file(文件功能)+ @author(开发者):
typescript
/**
* @file 用户信息页面
* @author 张三
*/方法注释
所有方法必须编写 JSDoc 注释,包含 @param、@returns:
typescript
/**
* 获取用户信息
* @param userId 用户 ID
* @returns 用户信息
*/
async function getUserInfo(userId: string): Promise<UserInfo> {
// ...
}复杂方法补充 @example:
typescript
/**
* 计算两个日期之间的天数
* @param startDate 开始日期
* @param endDate 结束日期
* @returns 天数
* @example
* const days = calculateDays(new Date("2024-01-01"), new Date("2024-01-31"));
* console.log(days); // 30
*/
function calculateDays(startDate: Date, endDate: Date): number {
// ...
}注释语言
- 注释语言以中文为主
- 技术关键字/API 保留英文
typescript
// 推荐
// 使用 HTTP GET 请求获取用户信息
const response = await HttpClient.get("/api/users");
// 不推荐
// Use HTTP GET request to get user information
const response = await HttpClient.get("/api/users");不可变性
原则
始终创建新对象,严禁修改原对象(Mutation):
typescript
// 错误:修改原对象
function updateUser(user: UserInfo, name: string): UserInfo {
user.name = name; // 直接修改了原对象!
return user;
}
// 正确:不可变性
function updateUser(user: UserInfo, name: string): UserInfo {
return {
...user,
name
};
}数组操作
typescript
// 错误:修改原数组
const numbers: number[] = [1, 2, 3];
numbers.push(4); // 修改了原数组
// 正确:创建新数组
const numbers: number[] = [1, 2, 3];
const newNumbers: number[] = [...numbers, 4];对象操作
typescript
// 错误:修改原对象
const user: UserInfo = { id: "1", name: "张三" };
user.name = "李四"; // 修改了原对象
// 正确:创建新对象
const user: UserInfo = { id: "1", name: "张三" };
const newUser: UserInfo = { ...user, name: "李四" };布局与交互约束
容器组件
优先使用 core/designsystem 封装的容器组件:
typescript
// 推荐
import { RowBase, ColumnBase, RowCenter, ColumnCenter } from "@core/designsystem";
ColumnBase() {
// ...
}均分布局
强制使用 layoutWeight(1) 实现,禁用 SpaceAround/SpaceBetween:
typescript
// 推荐
Row() {
Text("左侧").layoutWeight(1);
Text("右侧").layoutWeight(1);
}
// 不推荐
Row() {
Text("左侧");
Text("右侧");
}
.justifyContent(FlexAlign.SpaceAround)页面适配
使用百分比 / 布局权重 / 系统自适应单位,禁止硬编码固定宽高:
typescript
// 推荐
Column() {
// ...
}
.width("100%")
.height("100%")
// 不推荐(除非是图标等固定尺寸元素)
Column() {
// ...
}
.width(375)
.height(812)状态响应
VM 与 View 之间的状态同步,必须使用 @ObservedV2/@Trace 实现:
typescript
// 推荐
@ObservedV2
export class MyViewModel {
@Trace count: number = 0;
increment(): void {
this.count++; // 自动触发 UI 更新
}
}
// 不推荐
export class MyViewModel {
count: number = 0;
increment(): void {
this.count++;
// 需要手动刷新 UI
}
}错误处理
使用 try-catch
始终进行全面的错误处理:
typescript
async function fetchUserInfo(userId: string): Promise<UserInfo> {
try {
const response = await HttpClient.get(`/api/users/${userId}`);
return response.data;
} catch (error) {
console.error("获取用户信息失败:", error);
throw new Error("获取用户信息失败,请稍后重试");
}
}输入校验
始终校验用户输入:
typescript
function validateEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
function handleLogin(email: string, password: string): void {
if (!validateEmail(email)) {
throw new Error("邮箱格式不正确");
}
if (password.length < 6) {
throw new Error("密码长度不能少于 6 位");
}
// 执行登录逻辑
}文件组织
文件大小
- 通常为 200-400 行
- 单文件最大不超过 800 行
- 超过 800 行应考虑拆分
目录结构
按功能/领域组织,而非按类型组织:
// 推荐
packages/
└── user/
├── view/
├── viewmodels/
├── services/
└── models/
// 不推荐
src/
├── view/
│ ├── UserPage.ets
│ └── ProductPage.ets
├── viewmodels/
│ ├── UserViewModel.ets
│ └── ProductViewModel.ets
└── services/
├── UserService.ets
└── ProductService.ets代码质量自检清单
在标记工作完成之前:
- [ ] 代码易读且命名良好
- [ ] 函数体量小(<50 行)
- [ ] 文件内容聚焦(<800 行)
- [ ] 无深度嵌套(>4 层)
- [ ] 具备完善的错误处理
- [ ] 不存在 console.log 语句
- [ ] 不存在硬编码数值
- [ ] 所有类型注解完整
- [ ] 注释完整且准确