从动态对象到明确模型:改造 ArkTS 类型与数据结构
专栏HarmonyOS 三方库适配实战9/30核心问题怎样把“运行时随意长属性”的 TypeScript 数据改成可解释、可验证的 ArkTS 契约。摘要很多 TypeScript 工具库用any、索引签名、对象展开或运行时属性写入处理选项。迁移到 ArkTS 时真正要修的不是一个关键字而是数据契约允许哪些字段、默认值在哪里产生、未知字段怎样处理、错误如何返回。本文用文本规范化选项演示从动态字典到显式 class并用结果对象表达值和变化状态。代码已进入教学 HAR 并通过 API 22 编译但尚未做设备运行。先写清原始行为不要先改类型假设上游接受一个动态选项对象functionnormalize(input:string,options:Recordstring,unknown):string{letvalueinputif(options[trim]true){valuevalue.trim()}if(options[lowercase]true){valuevalue.toLowerCase()}returnvalue}这段代码隐藏了四个问题字段集合不明确、未知字段被静默忽略、值类型只能在运行时判断、调用方无法从签名知道默认值。官方从 TypeScript 到 ArkTS 的适配规则强调静态类型、固定对象布局并给出用明确类或接口替代动态写法的方向。改造前先记录行为trim、collapseWhitespace、lowercase的顺序是什么缺字段和false是否等价非布尔值是拒绝还是忽略空字符串是否允许。没有这一步类型更严格也可能把语义改错。第一步把配置变成显式 class以下代码与本地教学工程一致放在库模块的src/main/ets/model/NormalizeOptions.etsexportclassNormalizeOptions{trim:booleancollapseWhitespace:booleanlowercase:booleanconstructor(trim:boolean,collapseWhitespace:boolean,lowercase:boolean){this.trimtrimthis.collapseWhitespacecollapseWhitespacethis.lowercaselowercase}}显式构造器迫使调用方决定三个选项。若业务确实需要默认值可以新增语义明确的工厂方法例如NormalizeOptions.defaults()而不是让undefined在多个函数中各自解释。第二步让返回值也成为稳定契约只返回字符串时调用方不知道是否发生变化。教学库用结果对象同时返回值和状态exportclassNormalizationResult{value:stringchanged:booleanconstructor(value:string,changed:boolean){this.valuevaluethis.changedchanged}}changed的语义必须固定为“最终字符串是否与原输入不同”而不是“是否启用了某个选项”。否则启用trim但输入本来没有空白时会出现误导。第三步把处理顺序写进实现代码放在src/main/ets/core/TextNormalizer.etsimport{NormalizationResult,NormalizeOptions}from../model/NormalizeOptionsfunctioncollapseSpaces(input:string):string{returninput.replace(/\s/g, )}exportfunctionnormalizeText(input:string,options:NormalizeOptions):NormalizationResult{letvalue:stringinputif(options.trim){valuevalue.trim()}if(options.collapseWhitespace){valuecollapseSpaces(value)}if(options.lowercase){valuevalue.toLowerCase()}returnnewNormalizationResult(value,value!input)}顺序现在可读先裁剪两端再折叠空白最后小写。顺序属于 API 行为未来修改必须经过回归测试而不是当作内部细节随意调整。第四步在边界层处理不可信输入公开 ArkTS 调用已经要求NormalizeOptions但配置文件、网络 JSON 或 JS 互操作仍可能提供不可信数据。不要把动态数据直接传进核心函数在边界层逐字段读取、校验再构造明确模型。exportfunctioncreateDefaultOptions():NormalizeOptions{returnnewNormalizeOptions(true,true,false)}若需要解析 JSON应单独定义parseOptions并明确未知字段是报错还是忽略、缺失字段取什么默认值、类型错误如何表示。本文不伪造一个未编译的通用 JSON 解析器因为不同数据来源的接口与错误模型不同。图 1数据边界与核心模型示意图。动态数据只停留在边界层核心函数接收固定类型。正常、边界和错误输入怎么验用例输入选项期望normal-01 HarmonyOS Library true,true,falseHarmonyOS Librarychangedtruenormal-02 HarmonyOS Library true,true,trueharmonyos librarychangedtrueboundary-01HarmonyOStrue,true,false值不变changedfalseboundary-02true,true,false空字符串changedfalseerror-01非字符串来源在边界层拒绝不进入核心函数当前构建证明这些类型、构造器和调用路径被目标 SDK 接受由于没有运行测试表中的结果仍是契约期望而不是设备实测输出。第 16 篇会把向量迁移成 ArkTS 回归集。为什么不用“万能 Map”逃避建模Mapstring, Object看起来静态实际上仍把字段名、值类型和默认语义留给运行时。只有当键集合本来就开放例如用户自定义标签Map 才是合理模型。固定选项应优先使用 class 或明确接口。兼容性取舍严格模型可能暴露上游的宽松行为显式构造器会让以前被静默忽略的未知字段无法直接传入。这可能是改进也可能破坏既有调用方。适配记录应说明是否保留旧字段别名未知字段是否拒绝默认值是否与上游一致错误是抛异常还是返回结果对象。如果无法证明一致不要写“无损迁移”应写“公共契约已收窄待迁移上游测试确认”。图 2改造前后契约对比示意图。类型收窄后仍需上游测试确认行为兼容。本篇产物与下一篇门槛本篇产物是NormalizeOptions、NormalizationResult和normalizeText三个明确公共类型/符号。进入第 10 篇前必须能从单一入口导入它们并确认内部帮助函数没有被暴露。官方来源从 TypeScript 到 ArkTS 的适配规则用于静态类型、固定对象布局、对象字面量和结构类型的迁移依据。访问日期2026-10-18。ArkTS 迁移背景用于解释将部分运行时错误提前到开发期检查的目标。访问日期2026-10-18。验证声明本文展示的NormalizeOptions、NormalizationResult和normalizeText已写入本地教学 HAR2026-10-18 使用 HarmonyOS 6.0.2 ReleaseAPI 22完成assembleHar消费方通过包入口导入这些符号并完成assembleHap两个任务退出码均为 0。尚未执行 ArkTS 单元测试、模拟器或真机因此示例的行为表是待运行的契约不冒充设备结果。