在使用trae等ai工具来生成鸿蒙代码时,可能会遇到ai生成的代码里在DevEco Studio里出现语法报错的现象,这是因为鸿蒙的运行代码是ArkTS,而ai给出的代码是TypeScript甚至JavaScript。这时候就需要给ai配置相应的规则文件来告诉ai什么样的代码是正确的。
以下为给ai配置的配置文件内容:
---
ruleType: Always
description: HarmonyOS/ArkTS代码生成规范,TS到ArkTS转换的核心技术约束和最佳实践
---
# HarmonyOS ArkTS 代码生成规范
## 核心代码生成规范
### 1. 禁用any/unknown类型 - 核心规范
**规则**: `arkts-no-any-unknown` - 始终使用具体类型声明
#### 禁止的代码模式
```ts
// 以下代码模式严禁生成
function process(data: any) { } // 错误:参数使用any类型
let result: any = getData() // 错误:变量使用any类型
let config: unknown = JSON.parse(str) // 错误:使用unknown类型
function parseData(str: string) { // 错误:隐式any返回类型
return JSON.parse(str)
}
```
#### 推荐的代码模式
```ts
// 参数类型:根据使用场景确定具体类型
function processUser(data: UserInfo) { } // 正确:具体业务类型
function processConfig(data: Record<string, Object>) { } // 正确:通用结构类型
// 变量类型:明确标注或可推断
let result: UserInfo = getUserData() // 正确:明确类型
let count = 0 // 正确:可推断类型
// JSON.parse处理:必须显式标注返回类型
function parseConfig(str: string): Record<string, Object> { // 正确:明确返回类型
let data: Record<string, Object> = JSON.parse(str) // 正确:显式标注
return data
}
// 动态数据:使用Record或Object
function handleDynamicData(obj: Record<string, Object>) { // 正确:结构化类型
console.log(obj.name as string) // 正确:安全断言
}
```
---
### 2. 对象字面量类型标注 - 核心规范
**规则**: `arkts-no-untyped-obj-literals` - 对象字面量必须有明确类型
#### 禁止的代码模式
```ts
// 以下代码模式严禁生成
let obj = { name: 'test', age: 20 } // 错误:无类型对象
let data: Object = { id: 1, name: 'test' } // 错误:Object类型
let items: Object[] = [ // 错误:Object数组
{ name: 'item1' },
{ name: 'item2' }
]
// 函数参数传递对象字面量
emit('event', { action: 11, flag: true }) // 错误:无类型参数
// export default 对象
export default { // 错误:默认导出对象
onCreate() { console.log('init') }
}
// 无类型标注的对象字面量
let obj = { name: 'test', age: 20 } // 错误:无类型对象
let config: Object = { id: 1, name: 'test' } // 错误:Object类型
// 依赖structural typing的变量声明
let p = { x: 5, y: 10 } // 错误:TS支持structural typing但ArkTS不支持
```
#### 推荐的代码模式
```ts
// 方案1:定义class类型
class UserInfo {
name: string = ''
age: number = 0
}
let obj: UserInfo = { name: 'test', age: 20 } // 正确:明确类型
// 方案2:使用interface类型
interface ConfigItem {
id: number
name: string
}
let items: ConfigItem[] = [ // 正确:接口类型
{ id: 1, name: 'item1' },
{ id: 2, name: 'item2' }
]
// 方案3:函数参数先定义类型
function emit(event: string, data: Record<string, number | boolean>): void {}
let eventData: Record<string, number | boolean> = { // 正确:预定义变量
action: 11,
flag: true
}
emit('event', eventData)
// 方案4:从SDK导入类型
import image from '@ohos.multimedia.image'
const area: image.PositionArea = { // 正确:SDK类型
pixels: new ArrayBuffer(8),
offset: 0,
stride: 8,
region: { size: { height: 1, width: 2 }, x: 0, y: 0 }
}
// 方案5:默认导出改为class
class AppManager {
onCreate() { console.log('init') }
}
export default new AppManager() // 正确:class实例导出
// 方案6:对象字面量上下文类型推断
class Point {
x: number = 0
y: number = 0
}
function id_x_y(o: Point): Point {
return o
}
// 字面量初始化需要显式定义类型
let p: Point = { x: 5, y: 10 } // 正确:显式类型标注
id_x_y(p)
// id_x_y接受Point类型,字面量初始化生成一个Point的新实例
id_x_y({ x: 5, y: 10 }) // 正确:上下文类型推断
```
---
### 3. 禁用独立函数中的this - 重要规范
**规则**: `arkts-no-standalone-this` - this只能在类实例方法中使用
#### 禁止的代码模式
```ts
// 以下代码模式严禁生成
function handleClick() {
console.log(this.value) // 错误: 独立函数中的this
}
class Utils {
static value: string = 'test'
static getValue() {
return this.value // 错误: 静态方法中的this
}
}
// 函数式编程风格
const handler = function() {
return this.data // 错误: 函数表达式中的this
}
// 事件处理
button.onclick = function() {
this.disabled = true // 错误: 事件处理中的this
}
```
#### 推荐的代码模式
```ts
// 方案1:改为类的实例方法
class ClickHandler {
value: string = 'test'
handleClick() { // 正确: 实例方法可用this
console.log(this.value)
}
}
// 方案2:静态方法使用类名访问
class Utils {
static value: string = 'test'
static getValue(): string {
return Utils.value // 正确: 类名访问静态成员
}
}
// 方案3:参数传递替代this绑定
function handleData(data: UserData): void { // 正确: 参数传递
console.log(data.name)
}
class DataManager {
data: UserData = new UserData()
processData(): void {
handleData(this.data) // 正确: 显式传参
}
}
// 方案4:箭头函数捕获外层this
class ButtonManager {
disabled: boolean = false
setupButton(button: HTMLElement): void {
button.onclick = () => { // 正确: 箭头函数捕获this
this.disabled = true
}
}
}
```
---
### 4. 属性存在性检查 - 基础规范
**规则**: 只访问类型中已声明的属性,使用点操作符
#### 禁止的代码模式
```ts
// 以下代码模式严禁生成
class Point {
x: number = 0
y: number = 0
}
let p: Point = { x: 1, y: 2 }
console.log(p.z) // 错误: 访问未定义属性
console.log(p['x']) // 错误: 索引访问
let key = 'y'
console.log(p[key]) // 错误: 动态键访问
// 类型断言绕过检查
console.log((p as any).unknownProp) // 错误: any绕过检查
```
#### 推荐的代码模式
```ts
// 方案1:确保属性在类型中声明
class Point3D {
x: number = 0
y: number = 0
z: number = 0 // 正确: 显式声明需要的属性
}
let p: Point3D = { x: 1, y: 2, z: 3 }
console.log(p.z) // 正确: 访问已声明属性
// 方案2:使用点操作符访问
console.log(p.x) // 正确: 点操作符
console.log(p.y) // 正确: 点操作符
// 方案3:动态访问使用Record
let data: Record<string, number> = { // 正确: Record支持动态访问
x: 1,
y: 2,
z: 3
}
let key: string = 'x'
console.log(data[key]) // 正确: Record允许索引访问
// 方案4:可选属性处理
class UserProfile {
name: string = ''
email?: string // 正确: 可选属性
phone?: string
}
let user: UserProfile = { name: 'John' }
if (user.email) { // 正确: 检查可选属性
console.log(user.email)
}
```
---
### 5. 标识符未定义 - 基础规范
**规则**: 所有标识符必须正确导入、声明或在作用域内
#### 禁止的代码模式
```ts
// 以下代码模式严禁生成
console.log(undefinedVariable) // 错误: 未定义变量
someFunction() // 错误: 未导入函数
let result = SomeClass.staticMethod() // 错误: 未导入类
// 作用域问题
if (true) {
let temp = 10
}
console.log(temp) // 错误: 作用域外访问
// 拼写错误
class MyClass {
myMethod() {}
}
let obj = new MyClass()
obj.myMthod() // 错误: 方法名拼写错误
```
#### 推荐的代码模式
```ts
// 方案1:正确导入依赖
import { hilog } from '@ohos.hilog' // 正确: 导入系统API
import { UserService } from './services/user' // 正确: 导入业务模块
console.log(hilog.info(0, 'tag', 'message')) // 正确: 使用已导入模块
let users = UserService.getUsers() // 正确: 使用已导入服务
// 方案2:正确的变量声明和作用域
let temp: number = 10 // 正确: 外层声明
if (true) {
console.log(temp) // 正确: 访问外层变量
}
// 方案3:准确的标识符命名
class UserManager {
getUserData(): UserData { } // 正确: 方法定义
processUserInfo(): void { }
}
let manager = new UserManager()
manager.getUserData() // 正确: 正确的方法调用
manager.processUserInfo()
// 方案4:类型和值的正确引用
import { BusinessError } from '@ohos.base' // 正确: 导入类型
import notification from '@ohos.notificationManager' // 正确: 导入命名空间
function handleError(error: BusinessError): void { // 正确: 使用导入的类型
console.log(error.code)
}
let request: notification.NotificationRequest = { // 正确: 使用命名空间类型
id: 1,
content: {
contentType: notification.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
normal: { title: 'test', text: 'content' }
}
}
```
---
### 6. UI组件语法限制 - 特殊规范
**规则**: build/pageTransition/@Builder中只能包含UI组件语法
#### 禁止的代码模式
```ts
// 以下代码模式严禁生成
@Entry
@Component
struct HomePage {
@State message: string = 'Hello'
build() {
const temp = 1 // 错误: 变量声明
console.log('building UI') // 错误: 日志输出
if (this.message.length > 0) { // 错误: 复杂逻辑
return Column() {
Text(this.message)
}
}
let result = this.processData() // 错误: 函数调用
Column() {
Text(result)
}
}
@Builder
customComponent() {
let data = getData() // 错误: @Builder中的非UI语句
Text(data.title)
}
}
```
#### 推荐的代码模式
```ts
// 方案1:纯UI构造语法
@Entry
@Component
struct HomePage {
@State message: string = 'Hello'
@State processedData: string = ''
aboutToAppear() { // 正确: 业务逻辑放生命周期
this.processedData = this.processData()
}
build() { // 正确: 只包含UI组件
Column() {
Text(this.message)
.fontSize(16)
Text(this.processedData)
.fontSize(14)
Button('Click')
.onClick(() => this.handleClick())
}
.padding(16)
}
@Builder
customComponent(title: string) { // 正确: 纯UI构造
Row() {
Image($r('app.media.icon'))
.width(24)
.height(24)
Text(title)
.fontSize(16)
}
}
private processData(): string { // 正确: 业务逻辑在独立方法
return 'processed: ' + this.message
}
private handleClick(): void { // 正确: 事件处理在独立方法
this.message = 'Clicked'
}
}
// 方案2:数据驱动的条件渲染
@Component
struct ConditionalView {
@State items: string[] = []
build() {
Column() {
if (this.items.length > 0) { // 正确: 简单条件判断OK
ForEach(this.items, (item: string) => { // 正确: 数据驱动渲染
Text(item)
})
} else {
Text('No data')
}
}
}
}
```
---
## 补充代码生成规范
### 类型定义
```ts
// 使用interface替代对象字面量类型
错误: type User = { name: string; age: number }
正确: interface User { name: string; age: number }
```
### 类型转换和兼容性
```ts
// 使用显式类型转换
错误: let num: number = '123' as unknown as number
正确: let num: number = Number.parseInt('123')
// 数组需要明确元素类型
错误: let arr = [{ name: 'a' }, { name: 'b' }]
正确: let arr: User[] = [{ name: 'a' }, { name: 'b' }]
```
### 函数和方法
```ts
// 复杂函数显式标注返回类型
错误: function f(x: number) { return g(x) }
正确: function f(x: number): number { return g(x) }
// 使用标准库Number方法
错误: parseInt('42')
正确: Number.parseInt('42')
// catch不标注类型
错误: try {} catch (e: BusinessError) {}
正确: try {} catch (error) { let e = error as BusinessError }
```
### 对象操作
```ts
// 展开运算符限制 - 仅支持数组和数组派生类型
错误: let obj2 = { ...obj1, newProp: 'value' } // 对象展开
正确: let obj2 = new MyClass(); obj2.prop1 = obj1.prop1; obj2.newProp = 'value'
// 数组展开 - 支持
正确: let arr = [...arr1, ...arr2, newItem] // 数组展开
正确: let typed = [...new Uint8Array([1,2,3]), 4, 5] // TypedArray展开
// 剩余参数 - 支持
正确: function sum(...numbers: number[]): number { } // 剩余参数
正确: sum(...[1, 2, 3]) // 参数展开
// 使用箭头函数替代bind
错误: this.method.bind(this)
正确: () => this.method()
// 对象合并替代展开
错误: let merged = { ...base, newProp: value }
正确: let merged = Object.assign({}, base, { newProp: value }) // Object.assign
正确: let merged = { ...base }; merged.newProp = value // 逐个赋值
```
---
## 其他代码生成约束
### 基础语法规范
- 使用 `let`/`const` 替代 `var` 声明变量
- 使用箭头函数替代 `function` 表达式
- 泛型函数必须使用 `function` 声明,不能用箭头函数
- 类属性在类体中声明,不在构造函数参数中声明
### 类型系统约束
- 使用具体类型替代条件类型和映射类型
- 使用 `instanceof` 替代 `is` 类型保护
- 泛型类型参数必须显式标注,不依赖类型推断
- 使用继承替代交叉类型
### 对象和属性访问
- 使用点操作符访问属性,避免索引访问语法
- 使用 `Object.entries()` 替代 `for...in` 循环
- 正则表达式使用 `new RegExp()` 构造,不用字面量语法
### 模块导入导出
- 使用 ES6 `import/export` 语法
- `import` 语句必须在文件顶部
- 避免副作用导入,使用 `import * as` 形式
## 关键实践指导
### 动画与转场
- **优先改变transform属性**: 使用`scale`、`translate`、`rotate`和`opacity`实现动画
- **状态驱动动画**: 通过`animateTo`结合状态变化实现平滑动画
- **共享元素转场**: 使用`sharedTransition`实现页面间元素连续性
- **避免布局属性动画**: 禁止动画中修改`width`、`height`、`margin`、`padding`
### 组件复用与封装
- **@Reusable装饰器**: 提升列表等场景的渲染性能
- **attributeModifier模式**: 统一组件API风格,支持链式调用
- **合理数据传递**: 复杂对象使用`@Link`或`@ObjectLink`,避免深拷贝
- **生命周期管理**: 在`aboutToReuse`中更新组件数据
### 布局与性能
- **LazyForEach长列表**: 大量数据必须使用懒加载,避免`ForEach`
- **精简UI节点**: 减少不必要的布局嵌套
- **固定容器尺寸**: 为父容器设置明确宽高,减少重计算
- **条件渲染优化**: 合理选择`if/else`和`visibility`
### 手势与导航
- **HitTestMode控制**: 精确控制触摸事件传播和冲突
- **HMRouter导航**: 统一使用路由管理器,避免手动页面栈操作
- **标准组件优先**: 使用`Tabs`等系统组件构建导航
### 弹窗管理
- **合适弹窗选型**: 复杂场景使用Navigation Dialog,简单提示用CustomDialog
- **生命周期绑定**: 弹窗与页面生命周期正确绑定
- **键盘避让**: 确保弹窗内容不被软键盘遮挡