ArkTS 语法要点:TypeScript 的严格方言

要点

ArkTS 不是”带装饰器的 TypeScript”,而是 TypeScript 收紧后的严格方言:动态特性被大面积禁止,严格类型检查不是可配置项而是语言的一部分。会 TS 的人迁移过来,语法负担很小,真正的坎是那批 arkts-* 约束规则和状态管理装饰器的观测边界。这篇按”差异清单 → lint 规则 → 装饰器 → 文件分工”的顺序把坎一个个过掉。

ArkTS 与 TypeScript 的关系

三层关系:ArkTS 基于 TypeScript,大量基础语法(class、interface、泛型、箭头函数、模块)原样可用;它删掉了一批动态特性(any、解构、for…in 等),目的是让代码可被 AOT(Ahead-of-Time)静态编译成机器码,换取运行时性能和启动速度;它又通过装饰器扩展出声明式 UI 与状态观测,这部分是 TS 没有的。官方文档里有一份《从 TypeScript 到 ArkTS 适配规则》,是本篇差异清单的出处,细节以它为准。

与 TS 的高频差异清单

TS 写法 ArkTS 规则 ID 怎么改
any / unknown 禁止 arkts-no-any-unknown 写具体类型;跨语言边界受限使用 ESObject
let p = { x: 1 }(无类型字面量) 禁止 arkts-no-untyped-obj-literals 声明类型:let p: Point = { x: 1 },或用 class
type P = { x: number }(字面量当类型) 禁止 arkts-no-obj-literals-as-types 改用 interface 或 class
结构化类型(鸭子类型赋值) 受限 arkts-no-structural-typing 显式 implements / extends 建立关系
交叉类型 A & B 禁止 arkts-no-intersection-types 用继承组合出新类型
解构 const { a } = obj 禁止 arkts-no-destruct-decls / -assignment 逐个赋值:const a = obj.a
对象展开 {…obj} 受限 arkts-no-spread 逐字段赋值;数组场景部分可用
for…in、in 运算符 禁止 arkts-no-for-in / arkts-no-in 用 for…of 或显式判断
function 表达式 禁止 arkts-no-func-expressions 一律用箭头函数
function* 生成器 禁止 arkts-no-generators 没有直接等价物,改写普通循环/回调
throw ‘str’(抛非 Error) 禁止 arkts-limited-throw 只抛 Error 及其子类
Partial 等工具类型 受限 arkts-no-utility-types 仅 Partial / Required / Readonly / Record 可用
Reflect、动态改原型等 禁止 arkts-limited-stdlib 元编程能力整体不可用
@ts-ignore 禁止 arkts-strict-typing-required 不许用注释关检查,类型问题只能正面修

一个改写实例,感受一下”收紧”的力度:

// TypeScript 习惯写法,在 ArkTS 里逐条报错:
// const merge = (a, b) => ({ ...a, ...b })          // any 参数、无返回类型、展开、无类型字面量
// let cfg: { debug: boolean } = { debug: true }     // 字面量类型

// ArkTS 合法写法:
interface AppConfig {
  debug: boolean
}

const makeConfig = (debug: boolean): AppConfig => {
  return { debug: debug }   // 返回类型标了 AppConfig,字面量就有了归属
}

let cfg: AppConfig = makeConfig(true)

lint 规则在哪里、怎么读

这些约束不是可选的代码风格插件:DevEco Studio 对 .ets 文件实时检查,编译期同样强制。报错信息里会带规则 ID(社区文章常把禁 any 写成 arkts-no-any,官方迁移指南里的正式 ID 是 arkts-no-any-unknown,按 ID 搜索即可)。多数规则是错误级(不过编译),少数是警告级(如 arkts-limited-esobj 限制 ESObject 的使用),错误/警告的分级以当前 SDK 的迁移指南为准。遇到报错的第一反应不是绕过,而是按表格右侧的替代写法改——绕过手段(比如全用 ESObject)会让类型检查名存实亡。

状态管理装饰器:V1 全家

V1 是 API 9 时代沿用至今的状态管理体系,存量代码和大量三方库都在用:

装饰器 语义 关键约束
@State 组件内部状态,变化驱动本组件 UI 刷新 只观测第一层:数组项增删、对象整体赋值可见,嵌套属性变化不可见
@Prop 父到子单向同步,收到的是本地拷贝 子组件改它只影响自己;开销随数据变大(拷贝)
@Link 父子双向同步 父组件传值必须加 $ 前缀(建立引用而非拷贝)
@Provide / @Consume 跨层级注入与消费,免去逐层透传 同名匹配,重名会互相覆盖
@Observed + @ObjectLink 类实例 + 子组件接收,补上嵌套对象观测 @ObjectLink 变量不能本地初始化,只能由父组件传入

状态管理 V2 与两套体系现状

V2 从 API 12 起逐步提供,解决 V1 的两个老大难:观测只到第一层、属性级刷新做不到。对应关系:

V1 V2 对应 变化
@State @Local 名字即语义:组件本地状态
@Prop / @Link @Param + @Event 数据下行显式只读,子改父必须走回调,双向绑定被拆开
@Observed + @ObjectLink @ObservedV2 + @Trace 标注到类的属性级,嵌套对象的深层变化也能观测
@Provide / @Consume @Provider / @Consumer 语义延续,机制重写
— @Monitor 新增:声明式监听状态变化(回调可拿变化前后值)
@ObservedV2
class Cart {
  @Trace count: number = 0   // 标了 @Trace 的属性,改到第几层都刷新
}

@ComponentV2                 // 注意:V2 组件用 @ComponentV2,不是 @Component
struct CartBadge {
  @Local cart: Cart = new Cart()
  build() {
    Text(`${this.cart.count}`)
      .onClick(() => { this.cart.count += 1 })   // 属性级变化,直接触发
  }
}

现状要如实说:V2 是官方文档与迁移指南主推的方向,新项目建议直接上 V2;V1 没有被废弃,存量工程与三方库大量存在,短期内两套并存。硬约束是一条——V1 与 V2 不能混用:@Component 组件里写 @Local、@ComponentV2 组件里写 @State 都是直接报错。选型在一个工程内保持一致,别按组件心情混搭。

UI 层装饰器速览

@Component(组件,配 struct)、@Entry(页面根)、@Builder(无状态 UI 片段)在《第一个鸿蒙应用》里已用过。另外三个补充:@BuilderParam 让组件接收外部传入的 UI 片段(类似 Vue 的 slot);@Styles 抽取通用属性样式;@Extend 给特定组件扩展属性方法。入门记住前三个即可。

.ets、.ts 与 .d.ts 的分工

扩展名 角色 适用
.ets ArkTS 源文件,跑全部严格约束,可写声明式 UI 工程内业务代码默认选择
.ts 标准 TypeScript,不受 arkts-* 约束,不能写 ArkUI 从 Web 项目复用的纯逻辑、算法库
.d.ts 类型声明文件 给 .ts/.js 依赖补类型;系统 API 的类型声明也以声明文件形式提供

依赖方向有硬规则(arkts-no-ts-deps):.ets 可以 import .ts,.ts 不能 import .ets。所以”UI 层用 ets、纯逻辑下沉到 ts”的分层是自然结构;反过来想让一个 ts 工具文件回调 UI 状态,只能由 ets 侧把函数传进去。

常见问题

Q1: 一段 TS 代码粘进来满屏报错,从哪改起

按报错 ID 分类批量处理:先把 any 换成具体类型(arkts-no-any-unknown),再给所有对象字面量补类型归属(arkts-no-untyped-obj-literals),最后处理解构、展开这类结构性改动。前两类通常能消掉大半报错。

Q2: @State 嵌套对象不刷新,但我不想整体替换

这就是 V2 存在的理由:@ObservedV2 类 + @Trace 属性做属性级深度观测。V1 工程的等价方案是 @Observed + @ObjectLink 拆子组件。

Q3: @Component 里想用 @Param 报”装饰器不适用”

V1/V2 混用了。@Param 只属于 @ComponentV2。整个组件迁到 V2,或改用 V1 的 @Prop。

最佳实践与反模式

反模式一:把 TS 文件直接改后缀成 .ets 硬迁。约束是全量生效的,改后缀只会收获一份报错清单;正确做法是按 Q1 的顺序逐类修,或让纯逻辑留在 .ts 里被 ets 引用。

反模式二:拿 ESObject 当”更好的 any”到处用。ESObject 是为跨语言互操作预留的受限类型,超出边界使用会有警告,且丢掉类型检查的一切收益——等于在严格方言里重新过上无类型日子。

TS 本身的类型系统回顾(interface 与 implements、泛型约束、联合类型)可以翻《TypeScript 语法要点》——那些在 ArkTS 里依然成立,这篇讲的只是被收紧的部分。另一门”给 JS 系语言上严格枷锁”的对照样本是 Dart,见《Dart 语法要点》。

下一步

语言层过关后,日常开发缺的是查表:装饰器约束、组件参数、生命周期回调顺序、TaskPool 与 Worker 怎么选、高频报错对照——都在《ArkTS / ArkUI 基础知识参考字典》。

版本核实(撰写时检索,2025-01):ArkTS 为基于 TypeScript 的严格方言,严格类型检查不可配置、禁 any 与 @ts-ignore,规则 ID 与”仅 Partial/Required/Readonly/Record 可用”等细节出自官方《从 TypeScript 到 ArkTS 适配规则》(OpenHarmony/HarmonyOS 文档);状态管理 V2(@ComponentV2/@Local/@Param/@ObservedV2/@Trace/@Monitor 等)自 API 12 起提供,V1 仍被支持,两套不可混用;当前 Release SDK 配套 HarmonyOS NEXT 5.0(API 12)。规则分级与 API 可用性以 developer.huawei.com 官方文档为准。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇