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 = []
const
和 let
的原理和区别,以及在什么场景下使用,我在之前的文章 鸿蒙: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
方法,并传入了一个包含 location
和 name
属性的对象 作为参数。其中 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、性能优化、大厂面经,真诚推荐你关注我。
- 公众号:ByteCode
- 哔哩哔哩: space.bilibili.com/498153238
- 掘金: juejin.im/user/259450...
- 博客: hi-dhl.com
- Github: github.com/hi-dhl
最新文章
- 华为跟 Android 说再见,解读鸿蒙应用全部虚拟机化
- 鸿蒙:5 分钟秒懂 ArkTs,不能错过的知识点解析
- 学习鸿蒙,解决这几个关键问题
- 国内个人开发者太难了,APP备案保姆级过程
- 爆料 iPhone 史上最大的漏洞,你中招了吗
- 鸿蒙,流氓软件的终结者
- 使用 14 年的 API 被下线了
- Android 14 彻底终结大厂流氓应用
- 适配 Android 14,功能和权限的变更,你的应用受影响了吗
- Android 14 新增权限
- Android 13这些权限废弃,你的应用受影响了吗?
- 国外大厂面试题, 7 个 Android Lifecycle 重要的知识点
- Twitter 上有趣的代码
- 谁动了我的内存,揭秘 OOM 崩溃下降 90% 的秘密
- 反射技巧让你的性能提升 N 倍
- 90%人不懂的泛型局限性,泛型擦除,星投影
- 揭秘反射真的很耗时吗,射 10 万次耗时多久
- 影响性能的 Kotlin 代码(一)
- 揭秘 Kotlin 中的 == 和 ===
开源新项目
-
云同步编译工具(SyncKit),本地写代码,远程编译,欢迎前去查看 SyncKit
-
KtKit 小巧而实用,用 Kotlin 语言编写的工具库,欢迎前去查看 KtKit
-
最全、最新的 AndroidX Jetpack 相关组件的实战项目以及相关组件原理分析文章,正在逐渐增加 Jetpack 新成员,仓库持续更新,欢迎前去查看 AndroidX-Jetpack-Practice
-
LeetCode / 剑指 offer,包含多种解题思路、时间复杂度、空间复杂度分析,在线阅读