Skip to content

ArkTS 语言与状态管理

鸿蒙 UI 开发的语法基础。ArkTS 是 ArkUI 框架的应用开发语言:以 TypeScript 为基线的静态类型子集(禁用大部分动态能力),再叠加装饰器实现「状态驱动 UI」。示例基于 ArkTS / HarmonyOS NEXT 语境,需在 DevEco Studio 中验证。

ArkTS 与 TypeScript 的差异

官方定位是「TypeScript 的超集」但落地是收敛:ArkTS 只保留类型化写法,把 TS 的动态特性视为反模式并给出编译告警/错误。要改掉四个 TS 习惯:

  • any/unknown 逃避:所有变量需有确定类型。不确定类型用 union(如 string | null)或 Record 表达,而不是 as any 过关;
  • 禁用鸭子类型:对象必须来自明确声明(class/interface/类型别名),不接收运行时「摸出来」的额外属性。后端 JSON 一律显式声明 interface 后再映射;
  • 禁止对象字面量当类型推导主体let o = { a: 1 }o 类型会退化为字面量类型,后续 o.b = 2 编译报错——需要先声明 interface/class;
  • 函数式能力受限:部分 TS 高阶工具类型与结构性推断不可用,写业务时更依赖 class 与接口组合。

一个「声明模型 + 取数」的示例:

typescript
interface Article {
  id: string
  title: string
  summary?: string
}

class ArticleService {
  async fetchList(): Promise<Article[]> {
    const resp = await fetch('https://api.example.com/articles')
    const data = await resp.json() as Article[]
    return data
  }
}

要点:接口声明数据形状;as 断言收敛类型;async/await 全程可用。装饰器是 ArkTS 给类与变量加「能力」的入口,UI 状态全部靠它驱动。

装饰器体系:一类是「这是什么」,一类是「状态怎么变」

ArkTS 装饰器分两类心智:

  • 类型/入口装饰器@Component 标记 UI 组件、@Entry 标记页面入口组件、@Builder 标记自定义构建函数、@Styles/@Extend 做样式复用;
  • 状态装饰器@State(组件私有)、@Prop(父传子只读)、@Link(父子双向)、@ObjectLink(类对象深监听)、@Provide/@Consume(跨层共享)、@StorageLink 等(与 AppStorage 同步)。
typescript
@Component
struct Counter {
  @State count: number = 0

  build() {
    Row({ space: 8 }) {
      Button('减').onClick(() => { this.count-- })
      Text(`${this.count}`).fontSize(24)
      Button('加').onClick(() => { this.count++ })
    }
  }
}

V1 vs V2 要分清:经典装饰器(@State/@Prop/@Link…)是 V1 体系;API 12 起新增 V2 装饰器(@ComponentV2/@Local/@Param/@Once/@Event/@ObservedV2/@Trace)。新项目建议直接学 V2:粒度更细(@Trace 按属性更新而非整对象刷新)、限制更少、为跨端演进铺路。混用时注意一套组件不要混用两代局部状态装饰器。

父子与跨层通信

场景工具说明
父 → 子传值构造参数 + @Prop(V1)/ @Param(V2)只读同步
子 → 父通知回调函数 / @Link(V1)/ @Event(V2)事件上行
跨多层共享@Provide/@Consume(V1)或全局状态就近注入
全局会话态AppStorage / PersistentStorage持久化到磁盘
观察 class 内部@Observed + @ObjectLink(V1)深观测

一个 V2 风格示例:

typescript
@ObservedV2
class Cart {
  @Trace total: number = 0
}

@ComponentV2
struct CartBadge {
  @Local count: number = 0
  cart: Cart = new Cart()

  build() {
    Text(`购物车 ${this.cart.total}`)
  }
}

要点:状态只放「会被 UI 读取、需要触发刷新」的数据;列表项、临时局部值不必上装饰器。凡是 UI 依赖的变量修改后要反映到界面,都必须经过状态管理,绕开它去直接改变量不会触发刷新。

网络、异步与并发纪律

  • 网络用 @ohos.net.httphttp.createHttp())或 @kit.NetworkKit 的请求能力;原生并发用 TaskPool/Worker
  • 主线程不阻塞:耗时任务放异步或 TaskPool;UI 线程忙则掉帧;
  • 异步安全:装饰器字段更新要回到正确的任务上下文,避免在回调里直接对未标记可共享的对象做脏写;
  • 取消场景(组件销毁后仍回包)用 AbortController 或组件销毁时断开回调,防止状态泄漏。

常见坑速查

现象解法
as any 被拒编译报错显式 interface + 收窄
对象字面量无法加字段编译报错先声明 class/interface 类型
改变量不刷新UI 不变改用状态装饰器持有
深对象改了不刷界面不更新V1 用 @Observed/@ObjectLink,或升级 V2 @Trace
两代装饰器混用状态行为异常一个组件统一用一代局部装饰器
回调里 setState 野写入偶发崩溃/数据错乱路由到主线程 + 清理异步句柄

检查清单

  • [ ] 所有模型有显式 interface/class,无 any 逃逸;
  • [ ] 共享可变状态经状态装饰器管理,无旁路直改;
  • [ ] 明确当前用的是 V1 还是 V2,整组件保持一致;
  • [ ] 网络/耗时任务不进主线程,取消路径已清理;
  • [ ] 未经 DevEco Studio 实机的示例均已在页面标注验证要求。

基于 VitePress 构建 · 内容以知识共享方式沉淀