跳转至

HarmonyOS / ArkTS 编码风格

此文件使用 HarmonyOS 和 ArkTS 特定内容扩展 common/coding-style.md。

ArkTS 语言限制

ArkTS 是 TypeScript 的严格静态类型子集。违反这些约束会导致编译错误。

类型系统

  • 不可使用 any 或 unknown 类型 — 始终使用显式类型
  • 不可使用索引访问类型 — 直接使用类型名
  • 不可使用条件类型别名或 infer 关键字
  • 不可使用交叉类型 — 使用继承
  • 不可使用映射类型 — 使用类和常规惯用法
  • 类型注解中不可使用 typeof — 使用显式类型声明
  • 不可使用 as const 断言 — 使用显式类型注解
  • 不可使用结构化类型 — 使用继承、接口和类型别名
  • 除 Partial、Required、Readonly、Record 外,不可使用 TypeScript 工具类型
  • Record<K, V> 的索引表达式类型为 V | undefined
  • 在 catch 子句中省略类型注解(ArkTS 不支持 any/unknown)

函数和类

  • 不可使用函数表达式 — 使用箭头函数
  • 不可使用嵌套函数 — 使用 lambda
  • 不可使用生成器函数 — 多任务使用 async/await
  • 不可使用 Function.apply、Function.call、Function.bind — 对 this 使用传统 OOP
  • 不可使用构造函数类型 — 使用 lambda
  • 不可使用接口或对象类型的构造函数签名 — 使用方法或类
  • 不可在构造函数内声明类字段 — 在类主体中声明
  • 独立函数或静态方法中不可使用 this — 仅限实例方法内
  • 不可使用 new.target
  • 不可使用确定赋值断言(let v!: T)— 使用已初始化声明
  • 不可使用类字面量 — 引入命名类类型
  • 不可将类作为对象使用(赋值给变量)— 类声明引入的是类型而非值
  • 每个类只能有一个静态块 — 将所有静态语句集中在一起

对象和属性访问

  • 不可使用动态字段声明或 obj["field"] 访问 — 使用 obj.field 语法
  • 不可使用 delete 运算符 — 表示不存在时使用可空类型并赋值为 null
  • 不可赋值给原型 — 使用类和接口
  • 不可使用 in 运算符 — 使用 instanceof
  • 不可重新赋值对象方法 — 使用包装函数或继承
  • 不可使用 Symbol() API(Symbol.iterator 除外)
  • 不可使用 globalThis 或全局作用域 — 使用显式模块导出/导入
  • 不可将命名空间作为对象使用 — 使用类或模块
  • 不可在命名空间内使用语句 — 使用函数

解构赋值和展开

  • 不可使用解构赋值或变量声明 — 使用中间对象和逐字段访问
  • 不可使用解构赋值参数声明 — 直接传递参数并手动分配局部名称
  • 展开运算符仅可用于将数组(或数组派生类)展开到 rest 参数或数组字面量中

模块和导入

  • 不可使用 require() — 使用常规 import 语法
  • 不可使用 export = ... — 使用常规导出/导入
  • 不可使用导入断言 — 在 ArkTS 中,导入在编译时解析
  • 不可使用 UMD 模块
  • 模块名中不可使用通配符
  • 所有 import 语句必须写在所有其他语句之前
  • TypeScript 代码库不得通过 import 依赖 ArkTS 代码库(反向支持)

其他限制

  • 不可使用 var — 使用 let
  • 不可使用 for...in 循环 — 对数组使用常规 for 循环
  • 不可使用 with 语句
  • 不可使用 JSX 表达式
  • 不可使用 # 私有标识符 — 使用 private 关键字
  • 不可合并声明(类、接口、枚举)— 保持定义紧凑
  • 不可使用索引签名 — 使用数组
  • 逗号运算符仅限 for 循环内
  • 一元运算符 +、-、~ 仅限数值类型(无隐式字符串转换)
  • 枚举成员:显式初始化器仅限同类型的编译时表达式
  • 函数返回值类型推断受限 — 调用省略返回值类型的函数时显式指定

对象字面量

  • 仅当编译器能推断出对应类或接口时支持
  • 以下情况不支持:any/Object/object 类型、具有方法的类/接口、具有带参数构造函数的类、具有 readonly 字段的类

命名规则

  • 变量 / 函数:camelCase(例如:getUserInfo、goodsList)
  • 类 / 接口:PascalCase(例如:UserViewModel、IGoodsModel)
  • 常量:UPPER_SNAKE_CASE(例如:MAX_PAGE_SIZE、COLOR_PRIMARY)
  • 文件名:组件使用 PascalCase(例如:HomePage.ets),工具使用 camelCase

格式

  • 字符串优先使用双引号
  • 语句末尾添加分号
  • 绝对不要使用 var — 优先使用 const,其次使用 let
  • 为所有方法、参数和返回值添加完整类型注解

文件结构

  • 组件文件(.ets):每个文件一个 @ComponentV2
  • ViewModel 文件:每个文件一个 ViewModel 类
  • 模型文件:相关数据模型可以共存于同一文件
  • 文件控制在 400 行以内。接近 800 行时提取辅助函数

注释

  • 文件头:@file(文件目的)+ @author(开发者)— 如果项目已经使用文件头
  • 公共方法:在 JSDoc 中添加 @param、@returns。复杂方法添加 @example
  • 遵循项目现有文档语言。除非仓库已标准化中文注释,否则使用英文

错误处理

// 適切なエラーハンドリングで try/catch を使用する
try {
  const result = await riskyOperation()
  return result
} catch (error) {
  hilog.error(0x0000, 'TAG', 'Operation failed: %{public}s', error)
  throw new Error('User-friendly error message')
}

不可变性

遵循通用不可变性原则 — 创建新对象而不是修改原对象:

// BAD: ミューテーション
function updateUser(user: UserModel, name: string): UserModel {
  user.name = name  // 直接変更
  return user
}

// GOOD: イミュータブル — 新しいインスタンスを作成
function updateUser(user: UserModel, name: string): UserModel {
  const updated = new UserModel()
  updated.id = user.id
  updated.name = name
  updated.email = user.email
  return updated
}

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 ev/ECC