鸿蒙:揭晓 ArkTS,重塑语法,打造更健壮和可靠的代码

hi 大家好,我是 DHL。就职于美团、快手、小米。公众号:ByteCode,分享有用的原创文章,涉及鸿蒙、Android、Java、Kotlin、性能优化、大厂面经

我最近建了一个鸿蒙开发者交流群,群里有大佬说在 gitee 鸿蒙仓库中可以下载 DevEco Studio 4.0。于是我下载体验了一下,运行了官方提供示例项目 Shopping 出现了 422 个 Error 级别的错误 ,导致项目根本无法编译,于是我把这 422 个 Error 级别的错误 从头到尾改了一遍,可以理解为,我把核心代码重写了一遍,后面我会分享在 github 上。

出现这些错误的原因是因为 DevEco Studio 4.0 有一个非常重要的更新,进行代码编译时会对不符合 ArkTS 语法规则的代码进行告警。

告警分为两个级别:错误、警告。

  • 错误(Error): 必须要遵的规范。如果不遵从规范,将会导致程序编译失败
  • 警告(Warning): 推荐遵从的规范,尽管现在违反该规范不会影响编译流程,但是在将来,违反该规范可能将会导致程序编译失败,所以尽量遵守规范

这个更新既是开发者福音,有是开发者的噩梦,好处在于从编译器层面对开发规范进行了强制约束,有助于提高代码的可靠性和可维护性。可以帮助开发者编写更加健壮和可靠的代码。但是不好的一点,因为 TypeScript 的语言非常的自由,如果你没有按照社区的规范去写,那么升级到 DevEco Studio 4.0 你将面临大量的语法适配工作。

鸿蒙官方提供的示例 Shopping 就是一个经典的反面教材,导入 DevEco Studio 4.0 中运行出现了 422 个 Error 级别的错误

ArkTS 是在 TypeScript 的基础上扩展的,而 TypeScript 是在 JavaScript 的基础上扩展的,为了兼容 JavaScript,TypeScript 在很多方面都做了妥协。如果是移动端开发者,首次接触 TypeScript 和 JavaScript 的项目的时候,会觉得项目代码乱七八糟的,

核心原因 JavaScript 是非常的灵活的语言,开发者可以按照自己的想法去写,比如没有类型约束,一个变量可能初始化时是字符串,过一会儿又被赋值为数字,而 TypeScript 虽然提供了静态类型约束,但是不是强制的,从而导致了开发者可以按照自己的想法随意去写,只要项目可以运行起来就没有人会去改。

而鸿蒙在编译器层面上进一步加强了 ArkTS 语法规则的检查,有助于提高代码的可靠性和可维护性。帮助开发者编写更加健壮和可靠的代码。

ArkTS 限制了 TypeScript 很多逆天语法,这篇主要介绍我在运行官方示例项目 Shopping 遇到的错误,熟悉这些后,再运行官方示例项目,不用在去网上找答案了,当然你在网上也很难找到这些错误的解决方案。

本文所有代码都已经上传到了 github HarmonyPractice 仓库,欢迎点击 HarmonyPractice 仓库右上角 star,同时我也打开了 Discussions 功能,欢迎来 Discussions 一起讨论。

HarmonyPractice:https://github.com/hi-dhl/HarmonyPractice

不支持 any 或 unknown 类型,禁止使用 var

在 ArkTS 中要求强制使用静态类型,我在之前的文章 鸿蒙:5 分钟秒懂 ArkTs,不能错过的知识点解析 介绍过,没有看过的小伙伴可以去看一下。

如果能够推断出具体的类型,ArkTS 允许省略具体类型,否则需要指定具体类型,不然会报错。并且不能使用 any 和 unknown 类型。

为什么不能使用 any 和 unknown 类型 ,我举一个例子,以下代码在 TypeScript 中是可以运行的。

HarmonyPractice/Basic/entry/src/main/ets/syntax/TestType1. ts

ts 复制代码
示例1
let type: any
type = true;
type = 42;

示例2
getValue(type: any){ 

}
this.getValue(1)
this.getValue(true)

当你在看到这些代码的时候,不知心里作何感想,一个变量声明为 any 类型,初始可能是 boolean 类型,过一会儿又被赋值为数字,然而这些代码在 TypeScript 中是可以运行的。这种写法是非常的不安全,存在很大的安全隐患。

上面的示例,在 ArkTS 中是被允许的,编译器就会给你一个大大的错误提示。

所以在 ArkTS 中我们应该这么写:

HarmonyPractice/Basic/entry/src/main/ets/syntax/TestType2. ets

ts 复制代码
const type: number = 1;   // or  const type = 1
let bool: boolean = true; // or  let bool = true

// 如果你不确定类型,可以使用 object
let ob: object = []

constlet 的原理和区别,以及在什么场景下使用,我在之前的文章 鸿蒙:5 分钟秒懂 ArkTs,不能错过的知识点解析 做了详细的介绍。

需要注意的是在 TypeScript 中可以使用 var,但是不推荐,在 ArkTS 中禁止使用 var。因为是用 var 会带来很多问题。

ts 复制代码
if (true) {
    var message = "DHL";
}
console.log(message); // 输出 "DHL",而不是报错

我们希望运行上面的代码报错,但是在 TypeScript 中不仅不会报错,而且还会输出 "DHL",这是因为 var 声明的变量,在全局范围内都有效,因此在 if 语句外面也能获取到。

不支持解构赋值

解构赋值在 TypeScript 项目中非常的常见。解构赋值虽然方便,但是降低了代码的可读性和可维护性,先来看一个示例。示例中的代码在 TypeScript 中可以运行的。

HarmonyPractice/Basic/entry/src/main/ets/syntax/Destruct1. ts

ts 复制代码
let [head, ...tail] = [1, 2, 3, 4]; 

我们先来解释一下这段代码,示例中使用解构赋值从数组 [1, 2, 3, 4] 中提取值。解构赋值的语法 [head, ...tail] 表示我们想要从数组中提取第一个元素赋给 head,并将剩余的元素以数组的形式赋给 tail

因此,经过这行代码后,head 的值将是 1,而 tail 的值将是数组 [2, 3, 4]。解构赋值很方便,越方便越容易被开发者滥用,解构赋值可能会导致代码变得难以理解,尤其是复杂的嵌套结构,降低了代码的可读性和可维护性,因此在 ArkTS 禁止这样写,上面示例在 ArkTS 中会报错。

因此在 ArkTS 中我们应该这样写。

HarmonyPractice/Basic/entry/src/main/ets/syntax/Destruct2. ets

ts 复制代码
const data: Number[] = [1, 2, 3, 4];
const len = data.length;
let head = data[0];
let tail: Number[] = [];
for (let i = 1; i < len; ++i) {
  tail.push(data[i]);
}

更多示例,可以前往 github HarmonyPractice 仓库查看。

不支持参数解构的函数声明

函数的参数解构,在 TypeScript 项目中,也是非常的常见的写法,使用起来非常的方便。

HarmonyPractice/Basic/entry/src/main/ets/syntax/DestructParams1. ts

ts 复制代码
request({ location: [lat, lon], name: string}) {
// 在这个方法中,我们接收一个包含 location 和 name 属性的对象作为参数
// location 是一个数组,包含两个元素,分别是经度和纬度
// name 是一个字符串
}

testRequest() {
    // 在这个方法中,我们调用了上面定义的 request 方法,并传入一个对象作为参数
    this.request({ location: [10, 10], name: "DHL" })
}

我们先解释一下这段代码,在 testRequest 方法中,我们调用了 request 方法,并传入了一个包含 locationname 属性的对象 作为参数。其中 location 是一个数组,包含经度和纬度,而 name 是一个字符串。

参数的解构虽然方便,但是导致的结果代码变得难以理解,因此在 ArkTS 禁止这样写,上面示例在 ArkTS 中会报错。

因此在 ArkTS 中我们应该这样写。

HarmonyPractice/Basic/entry/src/main/ets/syntax/DestructParams2. ets

ts 复制代码
request(location: number[], name: string) {
    // location 是一个数组,包含两个元素,分别是经度和纬度
    // name 是一个字符串
}

testRequest() {
    // 在这个方法中,我们调用了上面定义的 request 函数,并传入一个对象作为参数
    this.request([10, 10], "DHL")
}

不支持在 catch 语句标注类型

在 ArkTS 中要求强制使用静态类型,如果能够推断出具体的类型,ArkTS 允许省略具体类型,否则需要指定具体类型。但是 catch 语句中有点不一样,先看示例代码。

HarmonyPractice/Basic/entry/src/main/ets/syntax/Exception1. ts

ts 复制代码
try {
  // ...
} catch (error: unknown) {
  // 处理异常
}

上面的代码在 TypeScript 中是可以正常运行的,这是因为 TypeScript 支持 any 或 unknown 类型,而 catch 语句中 error 只能声明为 any 或 unknown 类型,但是在 ArkTS 中运行,编译会给你一个大大的错误提示。

因为在 ArkTS 中不支持 any 或 unknown,所以这里应应省略类型标注。因此在 ArkTS 中代码如下所示。

HarmonyPractice/Basic/entry/src/main/ets/syntax/Exception2. ets

ts 复制代码
try {
  // ...
} catch (error) {
  // 处理异常
}

类型的别名与变量不能同名

在 TypeScript 中下面的代码是合法的。

HarmonyPractice/Basic/entry/src/main/ets/syntax/Type1. ts

ts 复制代码
let value: string
type value = number[] // 类型的别名与变量同名

但是在 ArkTS 中不允许这么写。

HarmonyPractice/Basic/entry/src/main/ets/syntax/Type2. ets

ts 复制代码
let value: string
type ages = number[] // 为避免名称冲突,此处不允许使用 value

类中仅支持一个静态块

在 TypeScript 中可以在类中使用多个静态代码块。

HarmonyPractice/Basic/entry/src/main/ets/syntax/Static1. ts

ts 复制代码
class Person{
  static {
    let name = "dhl"
  }
  static {
    let age = 10;
  }
}

虽然 TypeScript 支持,但是我还没见过有人会在类中定义多个静态代码块。在 ArkTS 中不允许类中有多个静态块,和 Kotlin 或者 Java 语言对齐的,如果使用多个,编译器会给出错误提示,因此我们需要将多个合并为 1 个。

不支持在 constructor 中声明类字段

在 TypeScript 中可以直接在类的 constructor 中声明类字段,代码如下所示。

HarmonyPractice/Basic/entry/src/main/ets/syntax/Constructor1. ts

ts 复制代码
class Person {
  constructor(
    private name: string
  ) {
    this.name = name;
  }

  getFullName(): string {
    return this.name;
  }
}

正如你所见,在 constructor 中声明字段 name,然后在 getFullName() 方法中可以使用 name,但是在 ArkTS 中不支持在 constructor 中声明类字段,编译器直接会报错。

在 ArkTS 中应该这么写,这和 Kotlin 或者 Java 在类中的使用是一样。

HarmonyPractice/Basic/entry/src/main/ets/syntax/Constructor2. ets

ts 复制代码
class Person {
  private name: string

  constructor(name: string) {
    this.name = name;
  }

  getFullName(): string {
    return this.name;
  }
}

数组必须仅包含可推断类型的元素

在 ArkTS 中,数组中的元素必须是可以根据上下文推断出来的类型,如果类型无法推断出来,则会报错,代码如下所示。

HarmonyPractice/Basic/entry/src/main/ets/syntax/Array1. ts

ts 复制代码
export const persons: Array<Person> = [
  { "name": "DHL" },
  { "name": "ByteCode" },
]

上面的代码在 TypeScript 中可以正常运行,当看到这段代码有没有觉得很奇怪,创建一个对象,这个对象的元素和类 Person 成员变量一致,就可以往数组中添加,我还是第一次见到代码可以这样写。切换到 ArkTS 会报错,禁止这样写。

在 ArkTS 中正确示例如下所示。

HarmonyPractice/Basic/entry/src/main/ets/syntax/Array2. ets

ts 复制代码
export const persons: Array<Person> = [
  new Person("DHL"),
  new Person("ByteCode"),
]

因为篇幅问题,这里我只介绍了运行官方示例项目中遇到的错误,后面我还会分享更多 ArkTs 语法约束。本文所有代码已上传到 github。

感谢你的阅读,写技术文章不易,如果文章对你有帮助,欢迎在看、点赞、分享给身边的朋友,你的点赞是我持续更新的动力

我在 github 上新建了一个 HarmonyPractice 仓库,这个仓库主要用于演示 ArkTS 语法规则、鸿蒙组件的使用,以及鸿蒙实战项目。

本文所有代码已上传到 HarmonyPractice 仓库 Basic 工程中,这个工程主要用于演示 ArkTS 的语法,会第一时间同步鸿蒙新增的语法约束,本文所有的代码均在 Basic 工程中,欢迎点击 HarmonyPractice 仓库右上角 star 以兹鼓励。

HarmonyPractice:https://github.com/hi-dhl/HarmonyPractice

👋👋👋 诚邀小伙伴们一起来共建 HarmonyPractice 仓库💪💪💪

  • 如果这个项目能够帮助到你,或者想第一时间收到项目的信息,欢迎点击仓库右上角 star
  • 如果你也想参与这个项目,欢迎提 PR
  • 如果你对这个项目有什么好的建议,欢迎来 Discussions 一起讨论,也可以私信我一起交流

鸿蒙还处于初期发展阶段,网上对鸿蒙问题的解答太少了,所以建了一个鸿蒙学习交流群,群里有很多大佬,相比于自己去摸索,通过与大家的沟通交流,效率会提高很多。诚邀各位小伙伴一起来打造一个良好的学习氛围沟通群。我在学习过程中也遇到了不少问题,有兴趣的小伙伴,可以看一下这篇文章,列举了我遇到的鸿蒙安装编译常见问题,以及解决方案。

目前群成员已经超过 200 人,不能扫描加入,喜欢或者正在学习鸿蒙的小伙伴,欢迎加我个人微信: hi-dhl,备注鸿蒙,我拉你进群。

2024,加油!

2024,一起见证彼此成长!


Hi 大家好,我是 DHL,在美团、快手、小米工作过。公众号:ByteCode ,分享有用的原创文章,涉及鸿蒙、Android、Java、Kotlin、性能优化、大厂面经,真诚推荐你关注我。


最新文章


开源新项目

  • 云同步编译工具(SyncKit),本地写代码,远程编译,欢迎前去查看 SyncKit

  • KtKit 小巧而实用,用 Kotlin 语言编写的工具库,欢迎前去查看 KtKit

  • 最全、最新的 AndroidX Jetpack 相关组件的实战项目以及相关组件原理分析文章,正在逐渐增加 Jetpack 新成员,仓库持续更新,欢迎前去查看 AndroidX-Jetpack-Practice

  • LeetCode / 剑指 offer,包含多种解题思路、时间复杂度、空间复杂度分析,在线阅读

相关推荐
pink大呲花几秒前
关于番外篇-CSS3新增特性
前端·css·css3
少年维持着烦恼.4 分钟前
第八章习题
前端·css·html
我是哈哈hh7 分钟前
HTML5和CSS3的进阶_HTML5和CSS3的新增特性
开发语言·前端·css·html·css3·html5·web
田本初25 分钟前
如何修改npm包
前端·npm·node.js
曾经的三心草28 分钟前
Mysql之约束与事件
android·数据库·mysql·事件·约束
明辉光焱1 小时前
[Electron]总结:如何创建Electron+Element Plus的项目
前端·javascript·electron
牧码岛1 小时前
Web前端之汉字排序、sort与localeCompare的介绍、编码顺序与字典顺序的区别
前端·javascript·web·web前端
开心工作室_kaic1 小时前
ssm111基于MVC的舞蹈网站的设计与实现+vue(论文+源码)_kaic
前端·vue.js·mvc
云空2 小时前
《InsCode AI IDE:编程新时代的引领者》
java·javascript·c++·ide·人工智能·python·php