07 ArkTS 基础类型与接口定义从 TypeScript 到鸿蒙的类型升级前言图07 ArkTS 基础类型与接口定义从 TypeScript 到鸿蒙的类型升级 运行效果截图HarmonyOS NEXTArkTS是 HarmonyOS NEXT 的官方开发语言基于 TypeScript 但在类型系统上做了更严格的约束禁止any类型、禁止动态属性访问、强制接口声明。这些限制让代码更安全、更可预测但也需要开发者改变一些 TypeScript 习惯。本文以鹿鹿·笔迹心理分析项目中的Models.ets数据模型文件为核心案例深入解析 ArkTS 的接口定义、联合类型、可选字段、只读数组和as const类型收窄等核心类型特性。官方文档·ArkTS 基础语法developer.huawei.comArkTS 与 TypeScript 差异developer.huawei.com图ArkTS 类型层次——从基础类型number/string/boolean到接口interface到数据实体Entity一、ArkTS 与 TypeScript 的关键差异1.1 类型约束升级ArkTS 在 TypeScript 基础上增加了以下强制规则规则TypeScript 允许ArkTS 要求any类型✅ 可以❌ 禁止动态属性访问obj[key]✅ 可以⚠️ 需要先as Recordstring, T未声明的接口扩展✅ 可以❌ 禁止需明确接口null和undefined的使用需配置需要可选链?.和空值合并??eval()✅ 可以❌ 禁止1.2 ArkTS 中使用 Record 处理动态访问// ❌ TypeScript 写法ArkTS 不允许constvaluesomeObj[dynamicKey];// ✅ ArkTS 写法constrecordsomeObjasRecordstring,Object;constvaluerecord[dynamicKey];// ✅ 实际项目中的应用路由参数读取constparamsthis.getUIContext().getRouter().getParams()asRecordstring,Object;if(paramstypeofparams[reportId]number){this.reportIdparams[reportId]asnumber;}二、基础类型系统2.1 原始类型ArkTS 支持以下原始类型// 数字类型整数和浮点数统一为 numberletage:number25;letscore:number3.14;letenergy:number0;// 字符串类型letname:string鹿鹿用户;letpath:stringpages/HomePage;// 布尔类型letisLoading:booleanfalse;letisBound:booleantrue;// null 和 undefined需显式声明letmaybeId:number|nullnull;letoptionalText:string|undefinedundefined;2.2 数组类型// 方式一T[] 语法推荐lettags:string[][温柔,细腻,专注];letscores:number[][78,65,92,50,80,70];// 方式二ArrayT 泛型语法letitems:ArrayArchiveEntity[];// 方式三只读数组不可修改元素constLABELS:readonlystring[][能量场,思维轴,行动力,情绪值,社交力,细节感];// ❌ 尝试修改只读数组会报错// LABELS.push(新维度); // 编译错误// LABELS[0] 修改; // 编译错误2.3 联合类型// 联合类型值可以是多个类型之一typeInputSourcecamera|gallery|handwrite;typeBoundMethodtap|qrcode|phone;// 函数参数使用联合类型functionprocessInput(source:InputSource):void{if(sourcecamera){// 处理相机输入}elseif(sourcegallery){// 处理相册输入}else{// 处理手写输入}}// 可空联合类型常见于可选的业务数据typeArchiveIdnumber|null;letcurrentArchiveId:ArchiveIdnull;三、接口定义interface3.1 项目数据实体接口鹿鹿项目的核心数据模型全部定义在Models.ets中// Models.ets — 完整数据实体接口定义// ① 用户实体exportinterfaceUserEntity{id?:number// 可选新创建时无 id数据库生成后有open_id?:string// 可选华为账号 Open ID本地用户为空name:string// 必须用户名称avatar?:string// 可选头像路径created_at:number// 必须创建时间戳Unix timestamp}// ② 档案实体一个档案 为某人建立的分析文件夹exportinterfaceArchiveEntity{id?:numberuser_id:number// 归属的用户 IDname:string// 档案名称如小明、自己emoji?:string// 头像 emoji如 relation?:string// 与档案主体的关系如自己、男友color?:string// 档案主题色last_record_at?:number// 最近一条记录的时间戳record_count:number// 分析记录总数created_at:number}// ③ 手写记录实体一次分析 一条手写记录exportinterfaceHandwritingEntity{id?:numberarchive_id?:numbersource:string// 输入来源camera | gallery | handwriteimage_path?:string// 图片文件路径本地ocr_text?:string// OCR 识别出的文字feature_json?:string// 6 维特征向量 JSON 字符串energy_score?:number// 能量得分 0-100device_type?:string// 设备类型word_count?:number// 识别字数write_duration?:number// 书写时长毫秒created_at:number}3.2 报告和关系实体// ④ 分析报告实体exportinterfaceReportEntity{id?:numberhandwriting_id:number// 关联的手写记录 IDarchive_id?:number// 关联的档案 IDpersonality_type?:string// 人格类型标签summary?:string// AI 综合解读文字radar_json?:string// 6 维雷达分数 JSON{ energy, thinking, action, emotion, social, detail }tags_json?:string// 画像标签 JSON 数组[温柔守护, 敏感细腻]created_at:number}// ⑤ 伴侣关系实体exportinterfaceRelationEntity{id?:numberuser_id:number// 当前用户 IDpartner_archive_id:number// 伴侣档案 IDbound_method?:string// 绑定方式tap | qrcode | phonematch_score?:number// 综合匹配度 0-100created_at:number}3.3 值对象接口除了数据库实体接口还有用于 UI 展示的值对象接口// 6 维雷达图分数从 radar_json 解析而来exportinterfaceRadarScores{energy:number// 能量场 0-100thinking:number// 思维轴 0-100action:number// 行动力 0-100emotion:number// 情绪值 0-100social:number// 社交力 0-100detail:number// 细节感 0-100}// 雷达图数据点用于 HandwritingRadar 组件exportinterfaceRadarPoint{label:string// 维度名称如能量场value:number// 维度分数 0-100}// AI 分析结果传递给 AnalyzingPage → ReportDetailPage 的中间态exportinterfaceAnalysisResult{ocrText:stringfeatureScores:RadarScores personalityType:stringsummary:stringtags:string[]energyScore:numberimagePath:stringanalyzedAt:number}四、可选字段与空值处理4.1 可选字段? 操作符interfaceUserEntity{id?:number// 可选? 表示该字段可以不存在name:string// 必须不加 ? 表示创建时必须提供}// 创建时不需要提供 id数据库自动生成constnewUser:UserEntity{name:鹿鹿用户,created_at:Date.now()// id 省略合法};// 从数据库读取后有 idconstexistingUser:UserEntity{id:1,name:鹿鹿用户,created_at:1700000000};4.2 可选链操作符?.// 安全访问可能为 null 或 undefined 的属性constarchiveNamearchive?.name??未知档案;constscorereport?.radar_json?JSON.parse(report.radar_json):null;// 多层链式访问constenergyScoreresult?.featureScores?.energy??0;// 函数调用当函数可能不存在时onCtaClick?.();// 如果 onCtaClick 是 undefined则不调用4.3 空值合并操作符??// ?? 只在左侧为 null 或 undefined 时取右侧的值// 注意区别于 |||| 在左侧为任何假值时都取右侧constuserIdAppStorage.getnumber(user_id)??1;// 默认用户 ID 1constuserNameAppStorage.getstring(user_name)??用户;// ?? vs ||constscorevalue??0;// value 0 时结果是 0?? 不处理 0constscore2value||0;// value 0 时结果是 0|| 把 0 当假值// 注意两者结果相同但当 value 时行为不同五、高级类型特性5.1 as const 类型收窄as const将数组或对象字面量升级为只读的精确字面量类型// 不使用 as const类型为 string[]可以 push/修改constTYPES[温和理性型,温柔守护型,敏感细腻型];// 使用 as const类型为 readonly [温和理性型, 温柔守护型, 敏感细腻型]exportconstPERSONALITY_TYPES[温和理性型,温柔守护型,敏感细腻型,紧绷专注型,开朗外放型,内敛深沉型]asconst;// 利用 typeof T[number] 提取值作为联合类型exporttypePersonalityTypetypeofPERSONALITY_TYPES[number];// 等价于温和理性型 | 温柔守护型 | 敏感细腻型 | 紧绷专注型 | 开朗外放型 | 内敛深沉型5.2 类型断言as// 将宽泛类型断言为具体类型constparamsthis.getUIContext().getRouter().getParams()asRecordstring,Object;constreportIdparams[reportId]asnumber;// 从 JSON 字符串解析时的类型断言constscoresJSON.parse(report.radar_json??{})asRadarScores;consttagsJSON.parse(report.tags_json??[])asstring[];// 注意类型断言不做运行时检查断言错误不会报错但会导致运行时异常5.3 泛型Generic Types// 简单泛型函数functionsafeGetT(key:string,defaultValue:T):T{returnAppStorage.getT(key)??defaultValue;}// 使用泛型constuserIdsafeGetnumber(user_id,1);constuserNamesafeGetstring(user_name,用户);// 泛型接口interfaceApiResponseT{code:number;message:string;data:T;}// 具体化typeUserResponseApiResponseUserEntity;typeArchiveListResponseApiResponseArchiveEntity[];六、JSON 序列化与反序列化6.1 数据库与实体的映射项目中有几个字段在数据库中存储为 JSON 字符串需要序列化/反序列化// 写入数据库前对象 → JSON 字符串constradarJsonJSON.stringify({energy:78,thinking:65,action:92,emotion:50,social:80,detail:70}asRadarScores);// 从数据库读取后JSON 字符串 → 对象constradarJSON.parse(report.radar_json??{})asRadarScores;consttagsJSON.parse(report.tags_json??[])asstring[];// 安全的解析防止 JSON 格式异常functionsafeParseJsonT(jsonStr:string|undefined,fallback:T):T{if(!jsonStr)returnfallback;try{returnJSON.parse(jsonStr)asT;}catch(e){hilog.warn(0x0000,Models,JSON 解析失败: %{public}s,jsonStr);returnfallback;}}// 使用constscoressafeParseJsonRadarScores(report.radar_json,{energy:50,thinking:50,action:50,emotion:50,social:50,detail:50});6.2 实体与 ValuesBucket 的映射// 实体接口 → RDB ValuesBucket写入数据库functiontoValuesBucket(entity:HandwritingEntity):relationalStore.ValuesBucket{return{archive_id:entity.archive_id??0,source:entity.source,image_path:entity.image_path??,ocr_text:entity.ocr_text??,feature_json:entity.feature_json??,energy_score:entity.energy_score??0,word_count:entity.word_count??0,created_at:entity.created_at};}七、ArkTS 编码规范总结7.1 接口设计最佳实践建议理由示例数据库实体 id 设为可选id?新建时无 idid?: number时间戳使用numberUnix 毫秒存储为整数created_at: number枚举值使用as const 联合类型类型安全的枚举camera | gallery复杂对象在数据库中存为 JSONSQLite 无 JSON 类型radar_json: string可选字段提供空值默认值避免 null 异常?? {}/?? []7.2 常见 ArkTS 类型错误// ❌ 错误使用 any 类型constdata:anyresponse.data;// ✅ 正确明确类型constdata:AnalysisResultresponse.dataasAnalysisResult;// ❌ 错误直接动态属性访问constnameobj[key];// ✅ 正确类型断言后访问constrecordobjasRecordstring,string;constnamerecord[key];// ❌ 错误不处理可空值constlengthstr.length;// str 可能为 undefined// ✅ 正确使用可选链constlengthstr?.length??0;八、注意事项与常见问题8.1 开发注意事项在实际开发过程中需特别注意以下几点API 兼容性部分接口仅在特定 HarmonyOS NEXT 版本中可用需做版本条件判断权限模型采用静态声明module.json5 动态申请requestPermissionsFromUser的两阶段授权生命周期合理使用aboutToAppear()和aboutToDisappear()管理资源初始化与释放状态同步跨页面数据通过 AppStorage 共享组件内状态使用State/Prop/Link装饰器8.2 常见错误与解决方案开发过程中的高频问题汇总错误现象可能原因解决方案权限被系统拒绝未在module.json5中静态声明添加requestPermissions权限配置项页面跳转后白屏路由路径未在main_pages.json注册检查并补充路由配置文件UI 状态不刷新状态变量未添加响应式装饰器为变量加State/Observed装饰器数据库查询返回空查询条件与存储数据格式不匹配使用hilog.debug打印 SQL 条件排查相机预览黑屏运行时相机权限未获取先调用requestPermissionsFromUser申请总结ArkTS 的类型系统在 TypeScript 基础上做了严格升级核心要点接口设计使用interface声明数据实体区分必须字段和可选字段?联合类型使用a | b | c替代string枚举提供编译时安全as const将常量数组升级为只读字面量类型配合typeof T[number]生成联合类型空值处理使用?.可选链和??空值合并安全处理 null/undefinedJSON 字段数据库中存 JSON 字符串读取后用JSON.parse() as T还原类型下一篇预告第08篇 ArkTS 类与静态方法设计如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力相关资源ArkTS 基础语法指南TypeScript 与 ArkTS 差异说明接口interface文档ArkTS 编码规范TypeScript 类型系统参考第06篇 目录结构第08篇 类与静态方法第09篇 异步编程