--- description: globs: alwaysApply: false --- # 鸿蒙ArkTS编程规则与最佳实践 ## 语法差异规则:ArkTS vs TypeScript 在需要更新经验规则记忆的时候,请及时更新.cursor\rules\cursorrules.mdc文件 ### 1. 空值检查规则 ```typescript // ❌ 错误: 未对可能为null的对象执行检查 this.dbObject.executeSql(sql); // ✅ 正确: 执行null检查 if (this.dbObject) { this.dbObject.executeSql(sql); } ``` ### 2. 解构赋值规则 ```typescript // ❌ 错误: ArkTS不支持解构赋值语法 for (const [key, value] of Object.entries(obj)) { // 处理逻辑 } // ✅ 正确: 使用传统循环方式 const keys = Object.keys(obj); for (let i = 0; i < keys.length; i++) { const key = keys[i]; const value = obj[key]; // 处理逻辑 } ``` ### 3. 异步API调用规则 ```typescript // ❌ 错误: 回调参数类型不匹配 dbStore.executeSql(sql, (err, result: ResultSet) => { // 处理逻辑 }); // ✅ 正确: 使用Promise模式 dbStore.executeSql(sql) .then(() => { // 成功处理 }) .catch((err: Error) => { // 错误处理 console.log(err.message); }); ``` ### 4. 计算属性名规则 ```typescript // ❌ 错误: 不支持计算属性名语法 const obj = { [CONSTANT.KEY]: value }; // ✅ 正确: 使用对象属性赋值语法 const obj = {}; obj[CONSTANT.KEY] = value; ``` ### 5. 数据类型规则 ```typescript // ❌ 错误: 使用any或未指定泛型类型 const items = new Set(); const map = new Map(); // ✅ 正确: 明确指定泛型类型 const items = new Set(); const map = new Map(); ``` ### 6. 错误对象类型规则 ```typescript // ❌ 错误: 使用隐式any类型的错误对象 try { // 代码 } catch (e) { console.log(`错误: ${e}`); } // ✅ 正确: 明确指定错误对象的类型 try { // 代码 } catch (e: Error) { console.log(`错误: ${e.message}`); } ``` ### 7. 类型声明与对象字面量规则 ```typescript // ❌ 错误: 对象字面量不能用作类型声明 const metadataToUpdate: { duration?: string, mimeType?: string, sampleRate?: string, trackCount?: string } = { /* 值 */ }; // ✅ 正确: 使用接口或类型别名定义类型 interface MediaMetadata { duration?: string; mimeType?: string; sampleRate?: string; trackCount?: string; } const metadataToUpdate: MediaMetadata = { /* 值 */ }; ``` ## 数据库操作最佳实践 ### 1. 表结构升级 ```typescript // ❌ 错误: 依赖回调处理的表结构升级 this.rdbStore.executeSql(tableInfoQuery, (err, result) => { // 处理逻辑 }); // ✅ 正确: 使用Promise模式并独立处理每个列的添加操作 this.rdbStore.executeSql(tableInfoQuery) .then(() => { // 为每个需要添加的列单独执行ALTER TABLE Object.keys(columnsToAdd).forEach(column => { const type = columnsToAdd[column]; this.rdbStore.executeSql(`ALTER TABLE ${tableName} ADD COLUMN ${column} ${type}`) .then(() => { /* 成功处理 */ }) .catch((err: Error) => { /* 错误处理 */ }); }); }); ``` ### 2. 资源释放 ```typescript // ❌ 错误: 未关闭ResultSet this.rdbStore.query(predicates, (resultSet) => { // 处理逻辑 }); // ✅ 正确: 确保关闭ResultSet this.rdbStore.query(predicates, (resultSet) => { try { // 处理逻辑 } finally { resultSet.close(); } }); ``` ### 3. 数据库查询安全处理 ```typescript // ❌ 错误: 不安全的列访问 const value = resultSet.getString(resultSet.getColumnIndex(columnName)); // ✅ 正确: 安全的列访问 const safeGet = (col: string) => { const index = resultSet.getColumnIndex(col); return index >= 0 ? resultSet.getString(index) || '' : ''; }; const value = safeGet(columnName); ``` ## 对象字面量规则 ### 1. 复杂对象初始化 ```typescript // ❌ 错误: 不支持复杂对象字面量初始化 const config = { complex: { nested: { value: someValue } } }; // ✅ 正确: 分步创建复杂对象 const config = {}; config.complex = {}; config.complex.nested = {}; config.complex.nested.value = someValue; ``` ### 2. 接口实现 ```typescript // ❌ 错误: 在类内部定义接口 class MediaTable { interface MediaMetadata { duration?: string; mimeType?: string; } } // ✅ 正确: 在类外部定义接口并导出 export interface MediaMetadata { duration?: string; mimeType?: string; } class MediaTable { // 类实现 } ``` ## UI数据处理规则 ### 1. 空值处理 ```typescript // ❌ 错误: 未处理空值或无效值 Text(this.currentSong.sampleRate) // ✅ 正确: 安全处理空值和无效值 Text(Utility.convertToKHz(this.currentSong?.sampleRate || '')) ``` ### 2. 数据转换函数 ```typescript // ❌ 错误: 直接在UI中转换数据 Text(`${Number(this.sampleRate) / 1000} KHz`) // ✅ 正确: 使用工具函数处理数据格式化 static convertToKHz(sampleRateHz: string|undefined): string { if(StrUtil.isEmpty(sampleRateHz) || sampleRateHz === undefined) { return '未知'; } try { const sampleRateNum = Number(sampleRateHz); if (isNaN(sampleRateNum) || sampleRateNum <= 0) { return '未知'; } return `${(sampleRateNum / 1000).toFixed(1)} KHz`; } catch (err) { return '未知'; } } // 在UI中使用 Text(Utility.convertToKHz(this.sampleRate)) ``` ## 命名规范 - 类名: PascalCase (例如 MediaTable) - 方法名: camelCase (例如 queryByParentPath) - 常量: UPPER_SNAKE_CASE (例如 DB_COLUMNS.FILE_PATH) - 私有属性: _camelCase (例如 _dbStore) - 接口名: PascalCase带I前缀或不带 (例如 IMediaMetadata 或 MediaMetadata) ## 异步编程最佳实践 ### 1. 避免回调地狱 ```typescript // ❌ 错误: 嵌套回调 methodA(() => { methodB(() => { methodC(() => { // 更多嵌套... }); }); }); // ✅ 正确: 使用Promise链或async/await methodA() .then(() => methodB()) .then(() => methodC()) .catch(error => console.error(error)); // 或使用async/await async function process() { try { await methodA(); await methodB(); await methodC(); } catch (error) { console.error(error); } } ``` ### 2. 异步状态更新 ```typescript // ❌ 错误: 在异步回调中直接更新状态而没有检查组件是否已销毁 fetchData(() => { this.data = result; // 组件可能已被销毁 }); // ✅ 正确: 添加组件生命周期检查 fetchData(() => { if (!this.mDestroyPage) { this.data = result; } }); ``` ## 文件和代码组织 ### 1. 导入导出规则 ```typescript // ❌ 错误: 混合默认导出和命名导出 export default class MediaTable { ... } export interface MediaMetadata { ... } // ✅ 正确: 明确区分默认导出和命名导出 // MediaTable.ets export default class MediaTable { ... } // MediaTypes.ets export interface MediaMetadata { ... } export interface AudioMetadata extends MediaMetadata { ... } ``` ### 2. 文件结构规则 ``` // ✅ 推荐的文件结构 /common /constants // 常量定义 /interfaces // 接口定义 /util // 工具类 /viewmodel // 视图模型 /view // UI组件 /controller // 控制器 ```