Skip to content

代码规范

概述

本文档定义了 HCompass 项目的代码规范,所有开发者都应遵循这些规范,以确保代码的一致性和可维护性。

核心技术栈约束

开发平台

  • HarmonyOS:使用 ArkTS/TypeScript 开发
  • API 版本:优先使用官方最新稳定版 API

状态管理

  • 强制使用 V2 版本:@ObservedV2 / AppStorageV2 / PersistenceV2
  • 禁用 V1 版本:禁止使用所有 V1 版本的状态管理 API

架构模式

  • MVVM 架构:严格遵循 MVVM 多模块架构
  • View 层职责:仅负责渲染,不包含业务逻辑
  • ViewModel 职责:封装所有业务逻辑

组件优先级

  1. 模块内复用组件
  2. core/components 跨模块通用组件
  3. IBest-UI-V2 组件库
  4. 禁止重复开发已有组件

代码风格

命名规范

变量和函数

使用 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 语句
  • [ ] 不存在硬编码数值
  • [ ] 所有类型注解完整
  • [ ] 注释完整且准确

下一步