@deveco-test/deveco-code 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/package.json +6 -5
  3. package/resources/deveco/skills/customize-deveco/.deveco-builtin +1 -0
  4. package/resources/deveco/skills/customize-deveco/SKILL.md +469 -0
  5. package/resources/deveco/skills/deveco-cli/.deveco-builtin +1 -0
  6. package/resources/deveco/skills/deveco-cli/SKILL.md +240 -0
  7. package/resources/deveco/skills/hmos-arkui-develop-skill/.deveco-builtin +1 -0
  8. package/resources/deveco/skills/hmos-arkui-develop-skill/SKILL.md +83 -0
  9. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/01-layout.md +629 -0
  10. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/02-basic-components.md +645 -0
  11. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/03-data-display.md +81 -0
  12. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/04-selectors.md +76 -0
  13. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/05-media.md +60 -0
  14. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/06-advanced.md +32 -0
  15. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/07-security.md +30 -0
  16. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/08-state-decorators.md +79 -0
  17. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/09-animation.md +111 -0
  18. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/10-gesture.md +59 -0
  19. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/11-dialog-menu.md +92 -0
  20. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/12-navigation.md +81 -0
  21. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/13-rendering.md +22 -0
  22. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/14-extension.md +22 -0
  23. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/15-theme-style.md +10 -0
  24. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/16-enums.md +87 -0
  25. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/17-resources.md +1379 -0
  26. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/18-error-code.md +24 -0
  27. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-apis/_index.md +75 -0
  28. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-rules/00-arkts-syntax.md +229 -0
  29. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-rules/01-import.md +116 -0
  30. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-rules/02-uicontext.md +56 -0
  31. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-rules/03-component.md +105 -0
  32. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-rules/04-build.md +41 -0
  33. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-rules/05-state.md +300 -0
  34. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-rules/06-rendering.md +67 -0
  35. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-rules/07-attribute-params.md +219 -0
  36. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-rules/08-navigation.md +102 -0
  37. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-rules/09-dialog.md +72 -0
  38. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-rules/10-style.md +90 -0
  39. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-rules/11-extension.md +54 -0
  40. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-rules/12-layout.md +69 -0
  41. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-rules/13-performance.md +27 -0
  42. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-rules/14-deprecated.md +28 -0
  43. package/resources/deveco/skills/hmos-arkui-develop-skill/references/quick-rules/_index.md +79 -0
  44. package/resources/deveco/skills/hmos-runtime-fix-skill/.deveco-builtin +1 -0
  45. package/resources/deveco/skills/hmos-runtime-fix-skill/SKILL.md +187 -0
  46. package/resources/deveco/skills/hmos-runtime-fix-skill/SKILL_CN.md +160 -0
  47. package/resources/deveco/skills/hmos-runtime-fix-skill/evals/evals.json +17 -0
  48. package/resources/deveco/skills/hmos-runtime-fix-skill/reference/businesserror_patterns.md +17 -0
  49. package/resources/deveco/skills/hmos-runtime-fix-skill/reference/error_patterns.md +31 -0
  50. package/resources/deveco/skills/hmos-runtime-fix-skill/reference/fault-mode-library.md +57 -0
  51. package/resources/deveco/skills/hmos-runtime-fix-skill/reference/outofmemoryerror_patterns.md +19 -0
  52. package/resources/deveco/skills/hmos-runtime-fix-skill/reference/rangeerror_patterns.md +15 -0
  53. package/resources/deveco/skills/hmos-runtime-fix-skill/reference/referenceerror_patterns.md +23 -0
  54. package/resources/deveco/skills/hmos-runtime-fix-skill/reference/syntaxerror_patterns.md +14 -0
  55. package/resources/deveco/skills/hmos-runtime-fix-skill/reference/typeerror_patterns.md +19 -0
  56. package/resources/deveco/skills/hmos-runtime-fix-skill/reference/urierror_patterns.md +17 -0
  57. package/resources/deveco/skills/hmos-runtime-fix-skill/scripts/collect-hilog.mjs +120 -0
  58. package/resources/deveco/skills/hmos-runtime-fix-skill/scripts/jscrash-report.mjs +138 -0
  59. package/resources/deveco/skills/hmos-runtime-fix-skill/scripts/parse-jscrash-log.mjs +126 -0
  60. package/resources/deveco/skills/hmos-runtime-fix-skill/scripts/shared/deveco-cli.mjs +79 -0
  61. package/resources/deveco/skills/hmos-runtime-fix-skill/scripts/shared/jscrash-parse.mjs +389 -0
  62. package/resources/deveco/skills/hmos-runtime-fix-skill/scripts/shared/utils.mjs +27 -0
@@ -0,0 +1,41 @@
1
+ # 4. build() 函数约束
2
+
3
+ ## 规则
4
+
5
+ | 规则 | 说明 | 错误码 |
6
+ |------|------|--------|
7
+ | `@Entry` 根节点必须为容器组件 | 根节点唯一且必需,**必须为容器组件**(`Column`/`Row`/`Stack`/`Navigation` 等) | — |
8
+ | `@Component` 根节点可为非容器 | 根节点唯一且必需,但可为非容器组件 | — |
9
+ | `ForEach` 禁止作为根节点 | 任何组件根节点都不能是 `ForEach`/`LazyForEach` | — |
10
+ | 禁止声明本地变量 | `let n = 1` 不允许 | — |
11
+ | 禁止 `console.info` | build() 中不允许直接 console.info(但方法/函数里可以) | — |
12
+ | 禁止本地作用域 | `{ ... }` 不允许 | — |
13
+ | 禁止调用非 `@Builder` 方法产出 UI | 只能调用 `@Builder` 装饰的方法来生成 UI 片段 | — |
14
+ | 禁止 `switch` | 用 `if` 替代 | — |
15
+ | 禁止三元表达式 | `? :` 不允许,用 `if` 渲染 | — |
16
+ | **禁止直接改变状态变量** | `this.counter += 1` 会导致循环渲染 | — |
17
+ | **sort/filter 陷阱** | `this.arr.sort().filter(...)` 中 `sort()` 改变原数组触发状态变更 → 循环 | — |
18
+ | **Button('label') 与 children 互斥** | `Button('x') { ... }` 同时传 label 和 children 报 **10905202**。要么 `Button('x')` 要么 `Button() { Text('x') }` | **10905202** |
19
+ | **嵌套 ForEach 参数名必须不同** | 嵌套 ForEach 每层用不同的 item 参数名(`row`/`cell`,不用 `item`/`item`) | — |
20
+ | **@Builder 返回 void,调用处不可链式** | @Builder 不返回值,不能在调用处链 `.onClick(...)` | — |
21
+
22
+ ## 常见错误对比
23
+
24
+ | ❌ 错误写法 | ✅ 正确写法 | 说明 |
25
+ |------------|-----------|------|
26
+ | `@Entry struct P { build() { ForEach(this.list, ...) } }` | `@Entry struct P { build() { Column() { ForEach(this.list, ...) } } }` | ForEach 不能做根节点 |
27
+ | `let n = this.compute()` 在 build() 中 | 把计算逻辑提到方法中,在 build() 中调用 | 禁止本地变量 |
28
+ | `console.info('x')` 在 build() 中 | 移到方法/事件回调中 | 禁止 console |
29
+ | `switch (this.type) { case 1: Text('a'); }` | `if (this.type === 1) { Text('a') }` | 用 if 替代 switch |
30
+ | `Text(this.flag ? 'yes' : 'no')` | `if (this.flag) { Text('yes') } else { Text('no') }` | 用 if 替代三元 |
31
+ | `this.counter += 1` 在 build() 中 | 放在事件回调 `.onClick(() => { this.counter += 1 })` | 不直接改状态变量 |
32
+ | `this.arr.sort().filter(x => x > 0)` | `this.arr.filter(x => x > 0).sort()` | sort() 改变原数组 |
33
+ | `Button('x') { Text('x') }`(同时传 label 和 children) | `Button('x')` 或 `Button() { Text('x') }` | 10905202 |
34
+ | 嵌套 ForEach 都叫 `item` | 外层 `row` 内层 `cell` 等不同名 | 参数名冲突 |
35
+
36
+ **根因**:AI 把 build() 当成普通函数来写,不理解声明式 UI 的渲染约束。
37
+
38
+ ## 参考
39
+
40
+ - 渲染控制(ForEach/LazyForEach/Repeat)见 [08-rendering](06-rendering.md)
41
+ - 容器直接子组件约束见 [16-layout](12-layout.md)
@@ -0,0 +1,300 @@
1
+ # 5. 状态管理(V1 + V2 + 混用)
2
+
3
+ > 本节包含 V1 装饰器、V2 装饰器、V1/V2 混用约束三部分。选 V1 范式读 V1 节,选 V2 范式读 V2 节,涉及跨版本传值时读混用节。
4
+
5
+ ---
6
+
7
+ ## V1 装饰器
8
+
9
+ ### @State
10
+
11
+ | 规则 | 说明 |
12
+ |------|------|
13
+ | 观察第一层 | 仅能观察到第一层的变化(赋值、数组项增删、Map/Set API 调用) |
14
+ | 嵌套对象需 @Observed/@ObjectLink | 深层属性变化无法被观察到,需要配合 @Observed 装饰类 + @ObjectLink 子组件 |
15
+ | 嵌套数组属性 push/splice 不刷新 | `project.tasks.push()` 不刷新(数组引用未变);需数组为 `@Observed class extends Array` + 子组件 `@ObjectLink` 接收数组实例本身 |
16
+ | 聚合值不自动刷新 | 已完成数/总进度无法自动观测子项属性变化,需通过回调手动 recompute |
17
+ | 不支持 undefined/null 类型 | 用具体类型 + 真实默认值 |
18
+
19
+ ### @Prop
20
+
21
+ | 规则 | 说明 |
22
+ |------|------|
23
+ | 单向同步 | 本地修改会被父组件更新覆盖 |
24
+ | 允许本地初始化 | 也可被外部初始化 |
25
+ | 拷贝数据源 | @Prop 装饰的变量在本地拷贝了数据源 |
26
+ | 本地有初始化则可选 | 初始化行为与 @State 一致;可被父组件传入覆盖 |
27
+ | 本地无初始化则必选 | 必须由父组件传入 |
28
+ | 支持父组件常规变量 | 常规变量对 @Prop 只做数值初始化,其变化不触发 UI 刷新;只有状态变量(@State 等)变化才触发刷新 |
29
+
30
+ ### @Link
31
+
32
+ | 规则 | 说明 |
33
+ |------|------|
34
+ | **必须外部初始化**,禁止本地初始化 | `@Link count: number = 0` 禁止 |
35
+ | 与数据源双向同步 | |
36
+ | 只能被 V1 状态变量初始化 | |
37
+ | 初始化语法 | 推荐 `Comp({ aLink: this.aState })`,不推荐 API9 前 `Comp({ aLink: $aState })` |
38
+
39
+ ### @ObjectLink
40
+
41
+ | 规则 | 说明 |
42
+ |------|------|
43
+ | **禁止本地初始化** | 必须从父组件传入 |
44
+ | **禁止整体赋值** | `this.objLink = ...` 不允许,只允许修改属性 |
45
+ | API 19 前类型必须为 `@Observed` class 实例 | 否则运行时告警且不刷新 |
46
+ | **不支持简单类型** | number/string/boolean 不能用 @ObjectLink,用 @Prop |
47
+
48
+ ### @Observed
49
+
50
+ | 规则 | 说明 |
51
+ |------|------|
52
+ | 装饰 class | 嵌套场景下,非简单类型的属性也需要被 @Observed 装饰 |
53
+ | 构造函数内修改成员不刷新 | 构造时实例尚未被代理,`this` 是原始对象,赋值不触发通知。只初始化,可变逻辑移到普通方法 |
54
+
55
+ ### @Provide / @Consume
56
+
57
+ | 规则 | 说明 |
58
+ |------|------|
59
+ | @Consume 不可以被外部初始化 | |
60
+ | @Provide 可被外部初始化,也可本地初始化 | |
61
+ | @Provide key 重复 | key 重复定义时框架抛运行时错误;需重复 key 用 `allowOverride` |
62
+
63
+ ### @StorageLink / @StorageProp / @LocalStorageLink / @LocalStorageProp
64
+
65
+ - 不可以被外部初始化,与 AppStorage/LocalStorage 自动绑定
66
+ - V1 storage API不能和@ObservedV2装饰类的实例混用:`AppStorage.setOrCreate`/`set`、`LocalStorage` 都是 V1 观察体系,存入 @ObservedV2 装饰的类对象后会发生运行时crash。@ObservedV2 对象走 `AppStorageV2`/`PersistenceV2`(仅 @ComponentV2 内)
67
+
68
+ ### @Watch
69
+
70
+ - **严格禁止**在 @Watch 回调中修改**自身被监视的变量**,否则无限循环
71
+ - @Watch 只放纯逻辑,**不在其中调 @Builder**(刷新异常)
72
+
73
+ ### 装饰器通用规则
74
+
75
+ - **每个属性只能用一个装饰器**,禁止叠加(如 `@State @Watch('fn') count: number = 0` 是合法的,但 `@State @Local count: number = 0` 报错)
76
+ - 一个属性不能同时被两个状态装饰器装饰
77
+
78
+ ### 类型注解必填
79
+ > 状态变量类型注解规则见 [00-arkts-syntax](00-arkts-syntax.md) Types 节(必须显式类型、禁止 any、对象字面量约束)。
80
+
81
+ ### 访问限定符约束
82
+
83
+ | 装饰器 | 允许 | 禁止 |
84
+ |--------|------|------|
85
+ | @State/@Prop/@Provide/@BuilderParam/常规变量 | 默认/public/private(private 阻止外部初始化) | protected(struct 无继承) |
86
+ | @StorageLink/@StorageProp/@LocalStorageLink/@LocalStorageProp/@Consume | 默认/private | public/protected |
87
+ | @Link/@ObjectLink | 默认/public | **private**(必须外部初始化)/protected |
88
+ | @Require + @State/@Prop/@Provide/@BuilderParam | 默认/public | **private**(与 @Require 矛盾)/protected |
89
+ | 所有装饰器 | — | **protected**(struct 无继承,所有 protected 产生告警) |
90
+
91
+ ---
92
+
93
+ ## @Builder 参数传递
94
+
95
+ ### 三种传递方式
96
+
97
+ | 方式 | 调用形式 | 状态变化刷新 | 用途 |
98
+ |------|---------|:-----------:|------|
99
+ | 按值(默认) | `builder(this.label)` 或 `builder(s: string)` | ❌ 不刷新 | 不依赖状态/仅初始渲染 |
100
+ | 按引用 | `builder({ k: this.label })`(单参数 + 对象字面量) | ✅ 刷新 | 依赖状态需刷新 |
101
+ | 按回调 (API 20+) | `builder(UIUtils.makeBinding(getter, setter))` | ✅ 刷新且可回写 | Builder 内需修改入参 |
102
+
103
+ ### 关键规则
104
+
105
+ | 规则 | 说明 |
106
+ |------|------|
107
+ | 形参类型必须是已声明的 interface/class | 禁止 `$$: { x: T }` 内联对象字面量 → **10605040** |
108
+ | **两个及以上参数不触发刷新** | 多参数、按值与按引用混用均不刷新,需合并为单个对象参数 |
109
+ | **@Builder 内禁止修改入参** | 简单类型不刷新,对象类型改属性报 **140109**(API 23+) |
110
+ | Builder 内创建子组件**不要传整个对象** | 拆成简单类型属性分别传入 |
111
+ | **禁止**在 UI 语句外调用 @Builder | 赋值给变量/数组后刷新异常 |
112
+ | **禁止**在 @Watch 回调内调 @Builder | 导致 UI 刷新异常 |
113
+ | `wrapBuilder` 泛型**必须是 tuple `[T]`** | 不能是 `WrappedBuilder<T>`,漏 `[]` 报 **10505001** |
114
+ | 尾随 lambda 调用自定义组件时,该组件必须且只能有一个 @BuilderParam | 多个槽位改用普通具名参数传 Builder |
115
+
116
+ ### wrapBuilder 正确用法
117
+
118
+ ```ts
119
+ // WRONG - 泛型漏 []
120
+ const w: WrappedBuilder<CardData> = wrapBuilder(CardBuilder) // ❌ 10505001
121
+
122
+ // RIGHT - 泛型写成 tuple [CardData]
123
+ const w: WrappedBuilder<[CardData]> = wrapBuilder(CardBuilder) // ✅
124
+ w.builder({ text: item }) // ✅ 调用 builder 方法
125
+ ```
126
+
127
+ ---
128
+
129
+ ## @Extend / @Styles
130
+
131
+ > 完整 @Extend/@Styles 规则见 [10-style](10-style.md)(仅全局定义、省略返回类型、禁止嵌套函数、动画约束)。
132
+
133
+ ---
134
+
135
+ ## @Observed / @ObjectLink 不刷新排查
136
+
137
+ ### 常见场景
138
+
139
+ | 场景 | 根因 | 解决 |
140
+ |------|------|------|
141
+ | 嵌套对象第二层不刷新 | @State 只代理第一层,`cousin.child.childId` 是第二层 | 内层类 @Observed + 子组件 @ObjectLink |
142
+ | @ObjectLink 整体赋值报错 | @ObjectLink 只读引用,`this.num = new Info()` 打断同步链 | 改属性;整体替换在父组件做 |
143
+ | 两层以上嵌套 | @ObjectLink 只代理直接接收的类 | N 层嵌套需要 N 个 @Observed + N 层 @ObjectLink 子组件 |
144
+ | 构造函数内修改不刷新 | 构造时实例未代理,`this` 是原始对象 | 构造函数只初始化,可变逻辑移到普通方法 |
145
+ | 嵌套数组属性 push/splice 不刷新 | 数组引用未变,@State 第一层观测不到 | 需 `@Observed class extends Array` + 子组件 @ObjectLink 接收数组实例 |
146
+ | 聚合值不刷新 | 深层属性变化父组件观测不到 | 聚合值存 @State,子项变化通过回调手动 recompute |
147
+ | LazyForEach 替换数组项不刷新 | LazyForEach 不监听 dataSource 内部变化 | 替换后调 `dataSource.notifyDataChanged(i)` |
148
+ | 同步渲染回调内改状态 |触发 "state changed during render",刷新被忽略 | 用 `setTimeout` 异步化 |
149
+
150
+ ### 排查五步法
151
+
152
+ 1. **依赖是否收集**:状态变量是否在 build 中被读取(ArkUI Inspector 查依赖)
153
+ 2. **值是否真变化**:打印赋值前后值
154
+ 3. **赋值是否可观察**:`UIUtils.getTarget(obj) === obj`(false = 已代理可观察);@ObservedV2 场景检查属性是否 @Trace
155
+ 4. **数据源与同步对象是否关联**:ForEach/LazyForEach 替换项后是否断链(`util.getHash` 比较引用)
156
+ 5. **组件更新函数是否执行**:是否在渲染回调中改了状态导致本次刷新被忽略
157
+
158
+ ---
159
+
160
+ ## V2 装饰器
161
+
162
+ ### @ObservedV2 / @Trace
163
+
164
+ | 规则 | 说明 |
165
+ |------|------|
166
+ | @ObservedV2 装饰 class,@Trace 装饰被观察属性 | V1 装饰器不能和 @ObservedV2 一起使用 |
167
+ | 深度观察需每层 @ObservedV2 + @Trace | 每一层 class 都要装饰 |
168
+
169
+ ### @Local
170
+
171
+ | 规则 | 说明 |
172
+ |------|------|
173
+ | **必须在组件内部初始化** | 不允许从外部传入初始化 |
174
+
175
+ ### @Param
176
+
177
+ | 规则 | 说明 |
178
+ |------|------|
179
+ | 可从父组件传入 | 默认单向同步(父到子) |
180
+ | 配合 @Event 实现双向同步 | |
181
+ | **@Param 只读** | 禁止在组件内重新赋值(`this.x = ...` 报 `Cannot assign to 'x' because it is a read-only property`) |
182
+
183
+ ### @Once
184
+
185
+ | 规则 | 说明 |
186
+ |------|------|
187
+ | 仅在组件首次创建时接收参数 | 后续父组件变化不更新 |
188
+
189
+ ### @Event
190
+
191
+ | 规则 | 说明 |
192
+ |------|------|
193
+ | 配合 @Param 实现子到父的回调通知 | |
194
+
195
+ ### @Provider / @Consumer (V2)
196
+
197
+ | 规则 | 说明 |
198
+ |------|------|
199
+ | @Provider 注入,@Consumer 消费 | 跨层级数据传递 |
200
+
201
+ ### @Computed (V2)
202
+
203
+ | 规则 | 说明 |
204
+ |------|------|
205
+ | 计算属性装饰器,自动缓存 | 仅在依赖的 @Trace 属性变化时重新计算 |
206
+
207
+ ### @Monitor (V2) / addMonitor / clearMonitor
208
+
209
+ | 规则 | 说明 | 错误码 |
210
+ |------|------|--------|
211
+ | addMonitor/clearMonitor 目标必须是 @ObservedV2 class(带 @Trace)或 @ComponentV2 实例 | **130000** |
212
+ | 回调必须是**命名函数**,不能是匿名函数 | **130002** |
213
+ | IMonitor 取值用 `mon.value<T>()?.now`,不是 `.after` | |
214
+
215
+ ```ts
216
+ // ❌ WRONG -- IMonitor 没有 'after',且漏泛型参数
217
+ @Monitor('searchKeywordValue')
218
+ onSearchKeywordChange(mon: IMonitor): void {
219
+ let keyword: string = mon.value?.after ?? '' // ❌
220
+ let keyword2: string = mon.value<string>().after ?? '' // ❌
221
+ }
222
+
223
+ // ✅ RIGHT -- 属性是 now,传类型参数
224
+ @Monitor('searchKeywordValue')
225
+ onSearchKeywordChange(mon: IMonitor): void {
226
+ let keyword: string = mon.value<string>()?.now ?? '' // ✅
227
+ let before: string = mon.value<string>()?.before ?? '' // ✅
228
+ }
229
+ ```
230
+
231
+ ### makeObserved
232
+
233
+ | 规则 | 说明 |
234
+ |------|------|
235
+ | 将普通对象转为 V2 可观测对象 | |
236
+ | 不支持 collections 类型和 @Sendable 装饰的 class | |
237
+ | 不支持非 object 类型、undefined、null | |
238
+ | 不支持 @ObservedV2 装饰的类 | |
239
+
240
+ ### applySyncUpdates / flushUpdates / flushUIUpdates
241
+
242
+ | 规则 | 说明 |
243
+ |------|------|
244
+ | 手动触发 V2 状态更新 | 在非 UI 线程修改状态后须手动调用刷新 UI |
245
+
246
+ ### 普通(未装饰)成员禁止外部初始化
247
+
248
+ `@ComponentV2` 内未装饰的普通成员变量只能在内部初始化,**禁止在调用处赋值**(`MyComp({ plain: 1 })` 不刷新且可能报错)。需从父组件传入的值必须用 `@Param` 装饰。
249
+
250
+ ---
251
+
252
+ ## V1/V2 混用
253
+
254
+ | 规则 | 说明 | 错误码 |
255
+ |------|------|--------|
256
+ | V1 装饰器禁止与 @ObservedV2 混用 | 维持禁止 | 编译错 |
257
+ | V2 → V1 禁止用装饰器直接接收 | V1 不支持用装饰器直接接收 @ObservedV2 装饰的 class | 编译错 |
258
+ | V1 @Link 只能被 V1 状态变量初始化 | | |
259
+ | V1→V2 需调 `enableV2Compatibility` | V1 状态变量传递到 V2 组件时,需调用 `UIUtils.enableV2Compatibility()` | |
260
+ | V2→V1 需调 `makeV1Observed` | V2 中优先声明成 V1 状态变量数据,并调用 `UIUtils.enableV2Compatibility(UIUtils.makeV1Observed())` | |
261
+ | 建议在 V2 组件构造处调用 | 避免变量被整体赋值后需要再次手动调用 | |
262
+ | 禁止双重代理 | 不使用 enableV2Compatibility 和 makeV1Observed 会导致双重代理问题 | |
263
+
264
+ ### 装饰器归属表
265
+
266
+ | 装饰器 | `@Component` (V1) | `@ComponentV2` (V2) |
267
+ |--------|:-----------------:|:-------------------:|
268
+ | @State/@Prop/@Link/@ObjectLink/@Provide/@Consume/@Watch | ✅ | ❌ 编译错 |
269
+ | @StorageLink/@StorageProp/@LocalStorageLink/@LocalStorageProp | ✅ | ❌ |
270
+ | @Local/@Param/@Once/@Event/@Provider/@Consumer/@Computed/@Monitor | ❌ 编译错 | ✅ |
271
+ | @ObservedV2/@Trace | ❌ | ✅ |
272
+ | @Builder/@BuilderParam/@Extend/@Styles/@Require | ✅ | ✅ |
273
+
274
+ ---
275
+
276
+ ## 常见错误对比
277
+
278
+ | ❌ 错误写法 | ✅ 正确写法 | 说明 |
279
+ |------------|-----------|------|
280
+ | `@State` 装饰组件入参 | @State 只能装饰内部变量,入参用 @Prop/@Param | 装饰器位置错误 |
281
+ | `@Link count: number = 0` | `@Link count: number` | @Link 禁止本地初始化 |
282
+ | `@ObjectLink info: Info = new Info()` | `@ObjectLink info: Info` | @ObjectLink 禁止本地初始化 |
283
+ | `@ObjectLink num: number` | @ObjectLink 不支持简单类型 | 用 @Prop 替代 |
284
+ | `@Consume theme: string = 'dark'` | `@Consume theme: string` | @Consume 禁止初始化 |
285
+ | `@Builder fn(s: string) { Text(s) }` 按值调用 `fn(this.label)` | 改单参数对象字面量按引用调用 | 按值不刷新 |
286
+ | `@Builder fn(a: A, b: B) { ... }` 两个参数 | 合并为单个对象参数 | 多参数不刷新 |
287
+ | Builder 内 `param.paramA = 'Yes'` | 用 MutableBinding 回调 | API 23 起报 140109 |
288
+ | `@Watch` 回调内调 `@Builder` | @Watch 只做逻辑,Builder 在 build 中调 | 刷新异常 |
289
+ | Builder 赋值给 `Array<CustomBuilder>` | 直接调用或传方法引用 | 刷新异常 |
290
+ | `@Observed 类构造函数内改 this 属性` | 构造函数只初始化,可变逻辑移到普通方法 | 实例未代理 |
291
+ | `@ComponentV2` 里用 `@State` | 用 @Local/@Param 等 V2 装饰器 | 混用编译错 |
292
+ | `@Component` 里用 `@Local` | 用 @State/@Prop 等 V1 装饰器 | 混用编译错 |
293
+ | 不调用 `enableV2Compatibility` 就跨 V1/V2 传值 | 需要兼容桥接 | 双重代理 |
294
+ | `@Local name: string` 在调用处 `<MyComp({ name: 'x' })>` | `@Param name: string` | @Local 只能内部初始化 |
295
+
296
+ ## 参考
297
+
298
+ - 错误码:**10505001**(成员名与链式方法冲突)、**10605040**(内联对象字面量作类型)、**140109**(Builder 内修改入参)
299
+ - @Extend/@Styles 完整规则见 [10-style](10-style.md)
300
+ - 类型注解完整规则见 [00-arkts-syntax](00-arkts-syntax.md) Types 节
@@ -0,0 +1,67 @@
1
+ # 8. 渲染控制约束
2
+
3
+ ## ForEach
4
+
5
+ | 规则 | 说明 | 错误码 |
6
+ |------|------|--------|
7
+ | **必须有第三个参数(keyGenerator)** | 缺少 key 生成器导致渲染异常 | — |
8
+ | key 用业务 ID,不用索引 | `(item, index) => index` 导致渲染不正确和性能差 | — |
9
+ | key 必须唯一 | 重复键值导致渲染异常 | — |
10
+ | 默认 key 有性能隐患 | 默认使用 `index + '__' + JSON.stringify(item)`,复杂对象 JSON 序列化占用大量内存 | — |
11
+ | bigint 等不可序列化类型会导致 jscrash | 必须提供自定义 key | — |
12
+ | 不建议与 LazyForEach 同时使用 | 同一滚动容器内不应混用 | — |
13
+ | 不建议用内容相同的数组项替换旧项 | 键值未变时数据变化不渲染 | — |
14
+ | **ForEach/LazyForEach 不是真实组件** | 不支持 `.layoutWeight()`/`.width()` 等通用布局属性(需包进容器再对容器设属性) | — |
15
+
16
+ ### LazyForEach
17
+
18
+ | 规则 | 说明 |
19
+ |------|------|
20
+ | 仅特定容器支持懒加载 | 仅 List/ListItemGroup/Grid/Swiper/WaterFlow 支持 |
21
+ | 容器内只能有一个 LazyForEach | 不建议同时包含 ListItem/ForEach/LazyForEach 或多个 LazyForEach |
22
+ | 每次迭代只产出一个根子组件 | 子组件生成函数有且只有一个根组件 |
23
+ | 子组件尺寸不能缺失 | 否则懒加载失效 |
24
+ | **dataSource 不可重新赋值** | 也不要用状态变量装 dataSource 再改它(不刷新) |
25
+ | **必须通过 DataChangeListener 更新** | `notifyDataChanged/notifyDataAdd/notifyDataDelete/notifyDatasetChange` |
26
+ | **Scroll 内放 LazyForEach 无效** | Scroll 不支持懒加载 |
27
+
28
+ ### Repeat (V2)
29
+
30
+ | 规则 | 说明 | 错误码 |
31
+ |------|------|--------|
32
+ | 仅在 @ComponentV2 中使用 | V1 用会错 | — |
33
+ | virtualScroll 模式需设 totalCount | `virtualScroll({ totalCount: arr.length })` | — |
34
+ | cachedCount 设在**滚动容器**上 | 不在 Repeat 链上(否则 **10505001**) | **10505001** |
35
+ | key() 必须唯一 | | — |
36
+
37
+ ```ts
38
+ // ❌ WRONG -- cachedCount 放 Repeat 链
39
+ List() { Repeat(this.list).virtualScroll({ totalCount: this.list.length }).cachedCount(3) }
40
+ // ✅ RIGHT
41
+ List() { Repeat(this.list).virtualScroll({ totalCount: this.list.length }) }.cachedCount(3)
42
+ ```
43
+
44
+ ### if/else
45
+
46
+ | 规则 | 说明 |
47
+ |------|------|
48
+ | 条件渲染"透明" | 父子组件之间的条件渲染不影响父组件对子组件的限制(如 Grid 内 if 内仍只能 GridItem) |
49
+ | 分支必须创建组件 | 空分支会语法错 |
50
+ | 分支切换不保留状态 | 旧子组件销毁、新建,不保留状态。需将状态提升到父组件 |
51
+ | 条件中不得改变应用状态 | 构造函数中的表达式不得更改应用程序状态 |
52
+
53
+ ## 常见错误对比
54
+
55
+ | ❌ 错误写法 | ✅ 正确写法 | 说明 |
56
+ |------------|-----------|------|
57
+ | `ForEach(this.list, item => { ... })` 缺第三个参数 | `(item: Item) => Text(item.name), (item: Item) => item.id.toString()` | 必须提供 keyGenerator |
58
+ | `(item, index) => index` 做 key | `(item: Item) => item.id.toString()` | 索引做 key 导致渲染不正确 |
59
+ | `LazyForEach` 的 dataSource 用状态变量并重新赋值 | 必须用 DataChangeListener 通知 | 重新赋值 dataSource 异常 |
60
+ | `LazyForEach` 放在 Scroll 里 | 仅 List/Grid/WaterFlow/Swiper 支持 | Scroll 不支持懒加载 |
61
+ | 同一容器内混用 ForEach 和 LazyForEach | 容器内只能有一个 LazyForEach | 不建议混用 |
62
+ | Repeat 链上 `.cachedCount(3)` | `.cachedCount(3)` 放在滚动容器上 | 10505001 |
63
+
64
+ ## 参考
65
+
66
+ - 容器直接子组件约束见 [16-layout](12-layout.md)
67
+ - @Observed 嵌套数组不刷新见 [05-state-v1](05-state.md)
@@ -0,0 +1,219 @@
1
+ # 9. 属性与 API 参数约束
2
+
3
+ ## 规则
4
+
5
+ ### 属性命名
6
+
7
+ | 规则 | 说明 |
8
+ |------|------|
9
+ | **禁止捏造不存在的属性名** | 不确定时必须检索确认 |
10
+ | **禁止使用缩写属性** | 无 `.bgColor()`、`.radius()`、`.textSize()` 等缩写 |
11
+ | **属性归属组件需匹配** | `.textOverflow()` 仅 Text 支持,`.objectFit()` 仅 Image 等媒体组件支持 |
12
+ | **Button 文字样式通过子组件设置** | 不直接支持 `.fontColor()` |
13
+
14
+ ### 枚举值
15
+
16
+ | 规则 | 说明 |
17
+ |------|------|
18
+ | **禁止用字符串代替枚举** | `.textAlign(TextAlign.Center)`,不能写 `'center'` |
19
+ | **枚举值大小写必须精确** | `FlexAlign.Start` 不能写 `FlexAlign.start` |
20
+ | **禁止猜测不存在的枚举** | 不确定时检索确认 |
21
+
22
+ ### 参数格式
23
+
24
+ | 规则 | 说明 |
25
+ |------|------|
26
+ | margin/padding 不支持多参数简写 | 用 `.margin({ top: 10, right: 20 })`,不写 `.margin(10, 20)` |
27
+ | Row/Column space 在构造器传入 | `Row({ space: 16 })`,不写 `Row().space(16)` |
28
+ | Stack 居中用 alignContent | `Stack().alignContent(Alignment.Center)`,不用 `.justifyContent()` |
29
+ | Flex 无 space | 用子组件 margin 替代 |
30
+ | 禁止借用其他框架写法 | 不用 `match_parent`/`wrap_content`,用 `'100%'`/`'auto'` |
31
+ | animateTo curve 必须为枚举 | `curve: Curve.Ease`,不写 `curve: 'ease'` |
32
+
33
+ ### 组件构造器
34
+
35
+ | 规则 | 说明 |
36
+ |------|------|
37
+ | Badge 必须包含 style | `Badge({ count: 5, style: { badgeSize: 16, badgeColor: Color.Red } })` |
38
+ | Badge 的 count 和 value 二选一 | 不能同时传 |
39
+ | Select 直接传数组 | `Select([{ value: 'A' }])`,不是嵌套 `{ options: [...] }` |
40
+ | bindPopup 需要 2 个参数 | `.bindPopup(this.show, { message: 'text' })` |
41
+ | WaterFlow 不接受 controller | `WaterFlow()` 空构造 |
42
+ | RichEditor 必须传 controller | `RichEditor({ controller: this.editor })` |
43
+ | overlay 必须传 CustomBuilder | 不能直接 `.overlay(Text('x'))`,需 @Builder 包装 |
44
+ | Scroll 传实例不传类 | `Scroll(new Scroller())`,不能 `Scroll(Scroller)` |
45
+ | ListItemGroup 无 divider 属性 | 用 List 的 `.divider()` 统一设置 |
46
+ | Refresh 构造器传 refreshing | `Refresh({ refreshing: this.isRefreshing })`,状态变化通过 `.onStateChange()` / `.onRefreshing()` 监听,非链式方法 |
47
+
48
+ ### 构造参数字段实测高发错
49
+
50
+ ```ts
51
+ // ❌ WRONG -- 凭记忆加错字段
52
+ TimePicker({ selected: new Date(), useMilitaryTime: true }) // useMilitaryTime 是 TimePickerDialog.show 的字段
53
+ PersistentStorage.persistProps([{ key: 'k', value: 'v' }]) // 正确字段是 defaultValue
54
+ PersistentStorage.persistProps([{ key: 'k', default: 'v' }]) // default 也错,是 defaultValue
55
+ Tabs(this.tabsController) { TabContent() {} } // 构造器参数是对象 { controller: ... }
56
+ MenuItem({ value: '复制', icon: $r('app.media.x') }) // 正确字段是 content + startIcon
57
+ Shape({ viewPort: {...} }) // Shape 构造参数是 PixelMap,viewPort 是链式方法
58
+
59
+ // ✅ RIGHT -- 拿不准时先声明带类型变量(编译器逐字段报错)
60
+ const opt: TimePickerOptions = { selected: new Date() }
61
+ TimePicker(opt)
62
+ ```
63
+
64
+ ### 回调参数类型
65
+
66
+ | 规则 | 说明 |
67
+ |------|------|
68
+ | 参数类型必须精确 | `onClick` 参数是 `ClickEvent`,不是 `GestureEvent` |
69
+ | 回调参数多为对象而非原始类型 | Video `onUpdate` 返回 `PlaybackInfo` 对象 |
70
+ | bindPopup onStateChange 参数是对象 | `{ isVisible }`,不是 `boolean` |
71
+ | TextPickerResult.index 是数组 | `result.index[0]`,不是 `result.index` |
72
+ | curves.springCurve 需要 4 个参数 | `curves.springCurve(10, 1, 228, 30)` |
73
+ | **选择器回调参数是联合类型** | 勿收窄,照编译器声明抄(见下方"常见错误") |
74
+
75
+ ### 资源名称
76
+
77
+ | 规则 | 说明 |
78
+ | ---------------------------- | ------------------------------------------------------------ |
79
+ | 禁止猜测系统符号名 | 系统符号名与直觉不同,必须查验证列表 |
80
+ | `$r('sys.color.*')` 多数无效 | 优先用 hex 如 `'#FFE84026'` |
81
+ | 媒体资源必须用 `$r` | `Image($r('app.media.icon'))`,禁止裸字符串路径 |
82
+ | sys.symbol 名不要猜 | `share→upload`、`settings→gearshape`、`search→magnifyingglass`、`home→house` |
83
+
84
+ ---
85
+
86
+ ## 臆造 API / 不存在的 API 清单
87
+
88
+ ### 实测高发臆造清单(写属性/方法名时默认怀疑,看到 `Did you mean` 直接采纳)
89
+
90
+ | 组件/类型 | ❌ 臆造的 | ✅ 正确写法 |
91
+ | --------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
92
+ | Swiper | `.previousMargin(40)` | `.prevMargin(40)` |
93
+ | RefreshStatus | `.InActive` / `.OverRefresh` | `.Inactive` / `.OverDrag` |
94
+ | ModalTransition | `.FULLSCREEN` / `.FULL` | 仅 `DEFAULT` / `NONE` / `ALPHA` |
95
+ | BlurStyle | `.BackgroundRegular`(驼峰) | `BACKGROUND_REGULAR`(SNAKE_CASE)或 `Thin`/`Regular`/`Thick` |
96
+ | Navigation | `.subtitle('...')` | Navigation 无 subtitle,用 `.title()` |
97
+ | Search | `.caretColor('#...')` | 不存在于 SearchAttribute |
98
+ | Text | `.alignItems(VerticalAlign.Bottom)` | alignItems 是容器方法;Text 用 `.textAlign()` |
99
+ | Radio / TextPicker | `.selectedColor('#...')` | 不存在于对应 Attribute |
100
+ | DatePicker | `.onDateAccept(...)` | 用 `.onChange` / `.onDateChange` |
101
+ | ColorFilter | `ColorFilter.matrix([...])` | 不存在于 typeof ColorFilter |
102
+ | DataChangeListener | `l.onDataReload()` | 用编译器建议方法名 |
103
+ | IMonitor | `monitor.before(path)` / `after(path)` | 不存在 |
104
+ | Shape 构造 | `Shape({ viewPort: {...} })` | `Shape()` + `.viewPort({...})` 链式 |
105
+ | Line 起点/终点 | `.startPoint({ x: 10, y: 20 })` | `.startPoint([10, 20])` 参数是 `Array<number>` |
106
+ | Search 搜索按钮 | `searchButton('搜索', { fontSize, color })` | `fontColor` 非 `color` |
107
+ | Text 文本溢出 | `.textOverflow(TextOverflow.Ellipsis)`(直传枚举) | 形参是 `TextOverflowOptions` 对象 |
108
+ | TextInput/TextArea 文本溢出 | `.textOverflow({ overflow: TextOverflow.Ellipsis })`(照搬 Text 写法) | 形参是 `TextOverflow` 枚举直传 |
109
+ | Search 占位符 | `.placeholder('请输入')`(当方法调) | 占位文本走构造器 `Search({ placeholder: '' })` |
110
+ | Radio 选中色 | `.selectedColor(Color.Red)` | `.radioStyle({ checkedBackgroundColor: Color.Red })` |
111
+ | Row/Column alignItems 轴 | Row 用 `HorizontalAlign.*` / Column 用 `VerticalAlign.*` | **交叉轴反直觉**:`Row().alignItems(VerticalAlign.Center)` |
112
+ | GestureGroup 子手势 | `GestureGroup(mode).children([tap, pan])` | 构造器变参:`GestureGroup(GestureMode.Sequence, tap, pan)` |
113
+ | NavigationOperation | `NavigationOperation.CANCEL` / `.process()` | 仅 `PUSH`/`POP`/`REPLACE`,无 CANCEL/PROCESS |
114
+ | Text.selection | `.selection([start, end])`(传数组) | 两个位置参数:`.selection(start, end)` |
115
+ | ButtonMode | `.displayMode(ButtonMode.NORMAL)` | `ButtonMode` 枚举不存在 |
116
+ | PanelType | `.MiniCard` / `.HalfCard` | `PanelType.Minibar` / `.Foldable` |
117
+ | ImageRenderMode | `ImageRenderingMode.ORIGINAL` | `ImageRenderMode.Original` |
118
+ | DataPanelType | `DataPanelType.Close` / `.Ring` | `DataPanelType.Circle` / `.Line` |
119
+ | **Stack** | `.justifyContent()` / `.alignItems()` 在 Stack 上 | Stack 对齐**只在构造器**:`Stack({ alignContent: Alignment.TopStart })`,无 `.justifyContent()` 也无 `.alignItems()` |
120
+ | **Flex space** | `Flex({ space: 10 })` | Flex 的 `space` 是 `{ main: LengthMetrics.vp(8) }`,不是数字 |
121
+ | **Switch** | `Switch(...)` 组件 | ArkUI 无 `Switch` 组件,用 `Toggle({ type: ToggleType.Switch, isOn })` |
122
+ | **ScrollAlign** vs **EdgeEffect** | `ScrollAlign.Start` 用于 `.edgeEffect()` 等混用 | `ScrollAlign` 用于 `scrollToIndex()`(Start/Center/End/Auto);`EdgeEffect` 用于 `.edgeEffect()`(Spring/Fade/None)— 两者不可混用 |
123
+ | **Canvas Settings** | `CanvasRenderingContext2DSettings` | 正确名字:`RenderingContextSettings`(`new CanvasRenderingContext2D(new RenderingContextSettings(true))`) |
124
+ | **List .alignList()** | `.alignList(ListItemAlign.X)` | List 无此属性,不存在 |
125
+ | **vp2px/px2vp** | 全局调用 `vp2px(20)` | 已废弃;用 `this.getUIContext().vp2px(20)` 或 `display.getDefaultDisplaySync().densityPixels` 换算 |
126
+ | **NavPathStack import** | `import { NavPathStack } from '@kit.ArkUI'` | NavPathStack 是全局类型,不需要 import |
127
+ | **onSizeChange 参数** | `.onSizeChange((w, h) => {})` | 签名:`(oldValue: SizeOptions, newValue: SizeOptions) => void` |
128
+ | **List .alignListItem()** | `.alignListItem(ListItemAlign.Center)` | 正确名是 `ListAlign` 不是 `ListItemAlignment`;List 属性是 `.alignListItem(ListItemAlign)` |
129
+ | **Slider .onGesture()** | `.onGesture()` | Slider 用 `.gesture()` 不是 `.onGesture()` |
130
+ | **TimePicker .fontSize()** | `.fontSize(16)` | `TimePicker` 用 `.textStyle(PickerTextStyle)` 不是 `.fontSize()` |
131
+ | **SaveButton .margin()** | `SaveButton().margin(8)` | 安全组件(SaveButton/PasteButton)接受 `.padding()` 但不接受 `.margin()` |
132
+ | **Tabs .barActiveColor()** | `.barActiveColor(Color.Blue)` | 不存在;用 `BottomTabBarStyle`/`SubTabBarStyle` 通过 `TabContent.tabBar()` 自定义 |
133
+ | **Navigation .onReady()** | `.onReady(() => {})` | Navigation 无 `.onReady()`,用 `.navDestination(builder)` 注册目标 |
134
+ | **$r('app.media.app_icon')** | `$r('app.media.app_icon')` | `app_icon` 非默认资源名;用 `$r('app.media.startIcon')` 或确认 resources/base/media 下实际文件名 |
135
+ | **.minWidth() / .minHeight()** | `.minWidth(100)` | 最小尺寸约束用 `.constraintSize({ minWidth: 100 })`,不是 `.minWidth()` |
136
+ | **.hideNavBar() 位置** | `NavDestination().hideNavBar(true)` | `.hideNavBar()` 属于 **Navigation** 非 NavDestination |
137
+
138
+ ### 其他已知不存在(禁止使用)
139
+
140
+ | 名称 | 说明 |
141
+ | ----------------------------------------------------- | ------------------------------------------------------------ |
142
+ | `WaterFlowController` | WaterFlow 无控制器 |
143
+ | `StarStyle` 枚举 | Rating starStyle 只接受自定义图片对象 |
144
+ | `SnapAlign` / `SnapPagination` | scrollSnap 不可用 |
145
+ | `curves.easeInOut()` | 用 `curves.initCurve(Curve.EaseInOut)` |
146
+ | `LengthMetrics.vp()` | LengthMetrics 是类型不能当值用 |
147
+ | `GradientDirection.BottomRight` | 正确名是 `RightBottom`(仅 TopLeft/TopRight/BottomLeft/RightBottom/LeftBottom) |
148
+ | `TextInputStyle.Normal` | 不存在,不调 `.style()` |
149
+ | `Curve.springMotion` / `Curve.responsiveSpringMotion` | 这些是 `curves` 命名空间**函数**,非 `Curve.*` 枚举成员 |
150
+ | `CircleShape`/`RectShape` 当组件用 | 这些是 shape 描述符类,非 UI 容器组件;画图形用 `Circle`/`Rect` 组件 |
151
+
152
+ ---
153
+
154
+ ## 常见错误对比
155
+
156
+ ### 参数名捏造
157
+
158
+ | ❌ 错误写法 | ✅ 正确写法 |
159
+ | ----------------------- | ----------------------------- |
160
+ | `.bgColor('#ff0000')` | `.backgroundColor('#ff0000')` |
161
+ | `.radius(8)` | `.borderRadius(8)` |
162
+ | `.textSize(16)` | `.fontSize(16)` |
163
+ | `.textColor(Color.Red)` | `.fontColor(Color.Red)` |
164
+ | `List({ gap: 10 })` | `List({ space: 10 })` |
165
+
166
+ ### 枚举值错误
167
+
168
+ | ❌ 错误写法 | ✅ 正确写法 |
169
+ | ----------------------------- | ------------------------------ |
170
+ | `.textAlign('center')` | `.textAlign(TextAlign.Center)` |
171
+ | `.fontWeight('bold')` | `.fontWeight(FontWeight.Bold)` |
172
+ | `PanelType.MiniCard` | `PanelType.Minibar` |
173
+ | `ImageRenderingMode.ORIGINAL` | `ImageRenderMode.Original` |
174
+
175
+ **Color 枚举仅 12 色**:`White`/`Black`/`Blue`/`Brown`/`Gray`/`Green`/`Grey`/`Orange`/`Pink`/`Red`/`Yellow`/`Transparent`。**不存在 `Gold`**,用 hex 字符串 `'#FFD700'` 或 `$r('sys.color.xxx')`。
176
+
177
+ **AppStorage API 签名**:`setOrCreate(key, value)` / `get(key)` / `set(key, value)` / `has(key)`,**没有 `.put()`**。
178
+
179
+ ### 回调参数类型错误
180
+
181
+ | ❌ 错误写法 | ✅ 正确写法 |
182
+ | ----------------------------------------------------------- | ------------------------------------------------------------ |
183
+ | `.onClick((event: GestureEvent) => {})` | `(event: ClickEvent) => {}` |
184
+ | `Video.onTimeUpdate((time: number) => {})` | `Video.onUpdate((data: PlaybackInfo) => { data.time })` |
185
+ | `Video.onPrepared((duration: number) => {})` | `Video.onPrepared((data: PreparedInfo) => { data.duration })` |
186
+ | `bindPopup onStateChange((vis: boolean) => {})` | `onStateChange((e: PopupStateEvent) => { e.isVisible })` |
187
+ | `curves.springCurve(0.3, 1.0)` | `curves.springCurve(10, 1, 228, 30)`(4 参数) |
188
+ | `TextPicker.onChange((value: string, index: number) => {})` | `(value: string \| string[], index: number \| number[]) => {}`(联合类型) |
189
+
190
+ ### 资源名称错误
191
+
192
+ | ❌ 错误写法 | ✅ 正确写法 |
193
+ | ----------------------------------------- | ---------------------------------- |
194
+ | `$r('sys.symbol.share')` | `$r('sys.symbol.upload')` |
195
+ | `$r('sys.symbol.settings')` | `$r('sys.symbol.gearshape')` |
196
+ | `$r('sys.symbol.search')` | `$r('sys.symbol.magnifyingglass')` |
197
+ | `$r('sys.symbol.home')` | `$r('sys.symbol.house')` |
198
+ | `$r('sys.color.ohos_id_color_emergency')` | `'#FFE84026'`(hex) |
199
+ | `$r('app.media.app_icon')` | 资源名 `app_icon` 不存在;用 `$r('app.media.startIcon')` 或实际存在的资源名 |
200
+
201
+ ---
202
+
203
+ ## 元规则:编译器是唯一真相
204
+
205
+ 1. **模型记忆不可靠**:22 处臆造 API 证明模型会自信地编造属性名
206
+ 2. **本地文档也可能滞后**:`quick-apis` 表可能与实际 d.ts 签名不一致
207
+ 3. **SDK 版本差异**:兼容 SDK 6.0.0(20) 时部分 API 需 26.0.0
208
+
209
+ **流程**:写 → 编译 → 看错误 → 按 `Did you mean` 修 → 再编译。拿不准的 API,先写最小调用让编译器报真实签名,再据此完善。
210
+
211
+ **泛型重载匹配**:调用 API 时确认参数数量和类型匹配某个已存在的重载,不要编造参数或传不存在的泛型类型参数。
212
+
213
+ ## 参考
214
+
215
+ - 类型注解见 [00-arkts-syntax](00-arkts-syntax.md)
216
+ - 空安全规则见 [00-arkts-syntax](00-arkts-syntax.md)
217
+ - @Extend/@Styles 返回类型见 [10-style](10-style.md)
218
+ - 废弃 API 替换见 [14-deprecated](14-deprecated.md)
219
+ - 相关错误码:**10505001**(属性不存在)、**10605038**(无类型对象字面量)