OpenHarmony从TypeScript到ArkTS的适配规则

本文通过提供简洁的约束,将标准的TypeScript代码重构为ArkTS代码。 尽管ArkTS是基于TypeScript设计的,但出于性能考虑,一些TypeScript的特性被限制了。因此,在ArkTS中,所有的TypeScript特性被分成三类。

  1. 完全支持的特性:原始代码无需任何修改。根据测试,对于已遵循最佳TypeScript实践的项目,代码库中90%到97%的内容可以保持原封不动。
  2. 部分支持的特性:需小规模的重构代码。例如,必须使用关键字let代替var来声明变量。
  3. 不支持的特性:需大规模的重构代码。例如,不支持any类型,所有使用any的代码都需要引入显式类型。

本文将介绍所有部分支持和所有不支持的特性,并提供重构代码的建议。根据本文提供的约束进行代码重构后代码仍为有效的TypeScript代码。对于没有提到的特性,则说明ArkTS完全支持。

示例

包含关键字var的原始TypeScript代码:

function addTen(x: number): number {
  var ten = 10;
  return x + ten;
}

重构后的代码:

function addTen(x: number): number {
  let ten = 10;
  return x + ten;
}

级别

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

  • 错误: 必须要遵从的约束。如果不遵从该约束,将会导致程序编译失败。
  • 警告: 推荐遵从的约束。尽管现在违反该约束不会影响编译流程,但是在将来,违反该约束可能将会导致程序编译失败。

不支持的特性

目前,不支持的特性主要包括:

  • 与降低运行时性能的动态类型相关的特性。
  • 需要编译器额外支持从而导致项目构建时间增加的特性。

根据开发者的反馈以及更多实际场景的数据,我们将来可能进一步缩小不支持特性的范围。

概述

本节罗列了ArkTS不支持或部分支持的TypeScript特性。

强制使用静态类型

ArkTS在设计之初,就确定了如下目标:

  • 因为代码的阅读频率高于编写频率,ArkTS代码需非常容易阅读和理解。
  • 以最小功耗快速执行代码,这点对于移动设备(ArkTS的目标设备)来说至关重要。

静态类型是ArkTS最重要的特性之一。使用静态类型有助于实现上述两个目标。如果程序采用静态类型,即所有类型在编译时都是已知的,那么开发者就能够容易理解代码中使用了哪些数据结构。同时,由于所有类型在程序实际运行前都是已知的,编译器可以提前验证代码的正确性,从而可以减少运行时的类型检查,有助于提升性能。

基于上述考虑,ArkTS中禁止使用any类型。

示例

// 不支持:
let res: any = some_api_function('hello', 'world');
// `res`是什么?错误代码的数字?字符串?对象?
// 该如何处理它?
// 支持:
class CallResult {
  public succeeded(): boolean { ... }
  public errorMessage(): string { ... }
}

let res: CallResult = some_api_function('hello', 'world');
if (!res.succeeded()) {
  console.log('Call failed: ' + res.errorMessage());
}

any类型在TypeScript中并不常见,只有大约1%的TypeScript代码库使用。一些代码检查工具(例如ESLint)也制定一系列规则来禁止使用any。因此,虽然禁止any将导致代码重构,但重构量很小,有助于整体性能提升。

禁止在运行时变更对象布局

为实现最佳性能,ArkTS要求在程序执行期间不能更改对象的布局。换句话说,ArkTS禁止以下行为:

  • 向对象中添加新的属性或方法。
  • 从对象中删除已有的属性或方法。
  • 将任意类型的值赋值给对象属性。

TypeScript编译器已经禁止了许多此类操作。然而,有些操作还是有可能绕过编译器的,例如,使用ArkTS不支持的as any进行转换。

示例

class Point {
  public x: number = 0
  public y: number = 0

  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
  }
}

// 无法从对象中删除某个属性,从而确保所有Point对象都具有属性x
let p1 = new Point(1.0, 1.0);
delete p1.x;           // 在TypeScript和ArkTS中,都会产生编译时错误
delete (p1 as any).x;  // 在TypeScript中不会报错;在ArkTS中会产生编译时错误

// Point类没有定义命名为z的属性,在程序运行时也无法添加该属性
let p2 = new Point(2.0, 2.0);
p2.z = 'Label';           // 在TypeScript和ArkTS中,都会产生编译时错误
(p2 as any).z = 'Label';   // 在TypeScript中不会报错;在ArkTS中会产生编译时错误

// 类的定义确保了所有Point对象只有属性x和y,并且无法被添加其他属性
let p3 = new Point(3.0, 3.0);
let prop = Symbol();      // 在TypeScript中不会报错;在ArkTS中会产生编译时错误
(p3 as any)[prop] = p3.x; // 在TypeScript中不会报错;在ArkTS中会产生编译时错误
p3[prop] = p3.x;          // 在TypeScript和ArkTS中,都会产生编译时错误

// 类的定义确保了所有Point对象的属性x和y都具有number类型,因此,无法将其他类型的值赋值给它们
let p4 = new Point(4.0, 4.0);
p4.x = 'Hello!';          // 在TypeScript和ArkTS中,都会产生编译时错误
(p4 as any).x = 'Hello!'; // 在TypeScript中不会报错;在ArkTS中会产生编译时错误

// 使用符合类定义的Point对象:
function distance(p1: Point, p2: Point): number {
  return Math.sqrt(
    (p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y)
  );
}
let p5 = new Point(5.0, 5.0);
let p6 = new Point(6.0, 6.0);
console.log('Distance between p5 and p6: ' + distance(p5, p6));

修改对象布局会影响代码的可读性以及运行时性能。从开发者的角度来说,在某处定义类,然后又在其他地方修改实际的对象布局,很容易引起困惑乃至引入错误。此外,这点还需要额外的运行时支持,增加了执行开销。这一点与静态类型的约束也冲突:既然已决定使用显式类型,为什么还需要添加或删除属性呢?

当前,只有少数项目允许在运行时变更对象布局,一些常用的代码检查工具也增加了相应的限制规则。这个约束只会导致少量代码重构,但会提升性能。

限制运算符的语义

为获得更好的性能并鼓励开发者编写更清晰的代码,ArkTS限制了一些运算符的语义。

示例

// 一元运算符`+`只能作用于数值类型:
let t = +42;   // 合法运算
let s = +'42'; // 编译时错误

使用额外的语义重载语言运算符会增加语言规范的复杂度,而且,开发者还被迫牢记所有可能的例外情况及对应的处理规则。在某些情况下,产生一些不必要的运行时开销。

当前只有不到1%的代码库使用该特性。因此,尽管限制运算符的语义需要重构代码,但重构量很小且非常容易操作,并且,通过重构能使代码更清晰、具备更高性能。

不支持 structural typing

假设两个不相关的类T和U拥有相同的publicAPI:

class T {
  public name: string = ''

  public greet(): void {
    console.log('Hello, ' + this.name);
  }
}

class U {
  public name: string = ''

  public greet(): void {
    console.log('Greetings, ' + this.name);
  }
}

能把类型为T的值赋给类型为U的变量吗?

let u: U = new T(); // 是否允许?

能把类型为T的值传递给接受类型为U的参数的函数吗?

function greeter(u: U) {
  console.log('To ' + u.name);
  u.greet();
}

let t: T = new T();
greeter(t); // 是否允许?

换句话说,我们将采取下面哪种方法呢:

  • T和U没有继承关系或没有implements相同的接口,但由于它们具有相同的publicAPI,它们“在某种程度上是相等的”,所以上述两个问题的答案都是“是”;
  • T和U没有继承关系或没有implements相同的接口,应当始终被视为完全不同的类型,因此上述两个问题的答案都是“否”。

采用第一种方法的语言支持structural typing,而采用第二种方法的语言则不支持structural typing。目前TypeScript支持structural typing,而ArkTS不支持。

structural typing是否有助于生成清晰、易理解的代码,关于这一点并没有定论。那为什么ArkTS不支持structural typing呢?

因为对structural typing的支持是一个重大的特性,需要在语言规范、编译器和运行时进行大量的考虑和仔细的实现。另外,由于ArkTS使用静态类型,运行时为了支持这个特性需要额外的性能开销。

鉴于此,当前我们还不支持该特性。根据实际场景的需求和反馈,我们后续会重新加以考虑。

那么要想成为一名鸿蒙高级开发,以上知识点是必须要掌握的,除此之外,还需要掌握一些鸿蒙应用开发相关的一些技术,需要我们共同去探索。

为了节省大家一些查找的时间,这边联合几位行业大佬,为大家准备了一份《OpenHarmony4.0&Next》的学习导图从入门到进阶再到南北向开发实战的一整套完整体系,想要学习了解更多鸿蒙开发的相关知识可以借鉴:《做鸿蒙应用开发到底学习些啥?》

除了上面整理的思维导图以外,这里还特别整理的一份《鸿蒙 (Harmony OS)开发学习手册》给大家进行参考学习:

一、入门必看

1. 应用开发导读(ArkTS)

2. ……

二、HarmonyOS 概念

1. 系统定义

2. 技术架构

3. 技术特性

4. 系统安全

5........

三、如何快速入门?《鸿蒙基础入门开发宝典!》

1. 基本概念

2. 构建第一个ArkTS应用

3. 构建第一个JS应用

4. ……

四、开发基础知识

1. 应用基础知识

2. 配置文件

3. 应用数据管理

4. 应用安全管理

5. 应用隐私保护

6. 三方应用调用管控机制

7. 资源分类与访问

8. 学习ArkTS语言

9. ……

五、基于ArkTS 开发

1. Ability开发

2. UI开发

3. 公共事件与通知

4. 窗口管理

5. 媒体

6. 安全

7. 网络与链接

8. 电话服务

9. 数据管理

10. 后台任务(Background Task)管理

11. 设备管理

12. 设备使用信息统计

13. DFX

14. 国际化开发

15. 折叠屏系列

16. ……

更多了解更多鸿蒙开发的相关知识可以参考:《鸿蒙开发学习指南》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/348085.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux sudo与/etc/sudoers

sudo介绍 sudo命令可以让普通用户在执行需要超级用户权限的命令时,临时提升为超级用户。例如,普通用户可以使用sudo执行系统管理任务,如安装软件、修改系统配置等。访问控制:sudo命令通过sudoers文件中的配置,可以对用…

什么是Spring

文章目录 什么是Spring什么是 IoC Spring的IoCDI的概念 什么是Spring Spring 是一个包含了众多工具方法的 IoC容器。 什么是 IoC Inversion of Control — 控制反转 在传统的开发中,假设A类依赖于B类,那么创建A对象实例就需要先new一个B类对象&#x…

【操作系统】实验八 proc文件系统

🕺作者: 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux 😘欢迎关注:👍点赞🙌收藏✍️留言 🏇码字不易,你的👍点赞🙌收藏❤️关注对我真的很重要&…

网络原理-初识(2)

协议分层 对于网络协议来说,往往分成几个层次进行定义. 网络通信的过程中,需要涉及到的细节,其实非常多.如果要有一个协议来完成网络通信,就需要约定好方方面面的内容,导致非常复杂. 而如果拆分的话,就十分复杂,庞大,因此需要分层. 什么是协议分层 即只有相邻的层次可以沟通,…

并查集与图

并查集与图 一、并查集概念实现原理代码实现查找根节点合并两颗树判断是否是同一棵树树的数量 二、图的基本概念定义分类完全图顶点的度连通图 三、图的存储结构分类邻接表邻接表的结构代码实现 邻接矩阵代码实现 四、图的遍历方式广度优先深度优先 五、最小生成树概念Kruskal算…

图中点的层次——树与图的广度优先遍历

问题描述 代码实现 #include <cstring> #include <iostream> #include <algorithm>using namespace std;const int N 1e5 10;int n, m; int h[N], ne[N * 2], e[N * 2], idx; int d[N]; // 从节点1到当前节点的距离 int q[N * 2]; // 数组模拟队列void ad…

BabylonJS 6.0文档 Deep Dive 摄像机(五):多视角(二)

1. 摄像机激活 一般来说&#xff0c;一个场景&#xff08;Scece&#xff09;只有一个激活相机&#xff0c;可以使用的activeCamera属性来指定它。但您也可以使用以下代码定义多个active相机来达成多视角的效果&#xff1a; scene.activeCameras.push(camera); scene.activeCa…

TensorRT英伟达官方示例解析(三)

系列文章目录 TensorRT英伟达官方示例解析&#xff08;一&#xff09; TensorRT英伟达官方示例解析&#xff08;二&#xff09; TensorRT英伟达官方示例解析&#xff08;三&#xff09; 文章目录 系列文章目录前言一、04-BuildEngineByONNXParser----pyTorch-ONNX-TensorRT生成…

探索设计模式的魅力:深入理解面向对象设计的深层原则与思维

如何同时提高一个软件系统的可维护性 和 可复用性是面向对象对象要解决的核心问题。 通过学习和应用设计模式&#xff0c;可以更加深入地理解面向对象的设计理念&#xff0c;从而帮助设计师改善自己的系统设计。但是&#xff0c;设计模式并不能够提供具有普遍性的设计指导原则。…

SAP ERP 物料主数据同步外围系统

物料主数据集成在很多项目是比较常见的需求&#xff0c;在做系统实现之前我们需要明确涉及的业务流程和需求范围&#xff0c;并且对每个系统的业务边界进行明确&#xff1a; 如果是从SAP ERP 向其他系统推送数据&#xff0c;并且实时性要求高的情况下&#xff0c;我一般倾向于在…

开关电源空载电流测试方法大全

空载电流测试原理 开关电源空载电流是指电源在没有负载的情况下所消耗的电流。空载电流的大小会影响到电源的工作效率和稳定性&#xff0c;因此测量开关电源的空载电流是非常必要的。 开关电源空载电流测试是在不接任何负载的条件下&#xff0c;用万用表、电流表或者其它专用测…

[MRCTF2020]Ez_bypass1

代码审计&#xff0c;要求gg和id的MD5值相等而gg和id的值不等或类型不等 相同MD5值的不同字符串_md5相同的不同字符串-CSDN博客 不过这道题好像只能用数组 下一步是passwd不能是纯数字&#xff0c;但是下一个判断又要passwd等于1234567 这里通过passwd1234567a实现绕过 原…

【操作系统】实验六 分析源代码

&#x1f57a;作者&#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f3c7;码字不易&#xff0c;你的&#x1f44d;点赞&#x1f64c;收藏❤️关注对我真的很重要&…

【grafana】使用教程

【grafana】使用教程 一、简介二、下载及安装及配置三、基本概念3.1 数据源&#xff08;Data Source&#xff09;3.2 仪表盘&#xff08;Dashboard&#xff09;3.3 Panel&#xff08;面板&#xff09;3.4 ROW&#xff08;行&#xff09;3.5 共享及自定义 四、常用可视化示例4.1…

【mongoDB】图形化界面工具(mongoDB Compass)

官网地址&#xff1a;https://www.mongodb.com/try/download/compass 下载完之后直接安装 桌面上会产生一个快捷方式 双击就会进入mongoDB图形化界面工具

IP组播地址

目录 1.硬件组播 2.因特网范围内的组播 IP组播地址让源设备能够将分组发送给一组设备。属于多播组的设备将被分配一个组播组IP地址 组播地址范围为224.0.0.0~239.255.255.255(D类地址)&#xff0c;一个D类地址表示一个组播组。只能用作分组的目标地址。源地址总是为单播地址…

Vue+OpenLayers7入门到实战:鹰眼控件简单介绍,并使用OpenLayers7在地图上添加鹰眼控件

返回《Vue+OpenLayers7》专栏目录:Vue+OpenLayers7 前言 本章介绍OpenLayers7添加鹰眼控件到地图上的功能。 在OpenLayers中,想要实现鹰眼控件,必须要新建一个数据源,且不能跟其他图层混用,相当于鹰眼是一个单独图层。 补充知识,鹰眼控件是什么? 鹰眼控件是一种在地…

AI教我学编程之SQL Server常见指令以及数据类型

前言 今天在工作的过程中&#xff0c;遇到了许多常见的属性&#xff0c;在此做下记录&#xff0c;方便以后查询 目录 SQL Server 常见指令 对话AI 光有概念怎么行 阶段总结 SQL Server关键字 边学边练 数据类型 看图说话 对话AI 数据类型我知道 括号里的神秘数字 疑问 边练…

彩色图像处理之彩色图像分割的python实现——数字图像处理

原理 彩色图像分割是图像处理领域的一个重要技术&#xff0c;它旨在将一幅彩色图像划分为多个区域或对象。其基本原理包括以下几个方面&#xff1a; 像素特征的提取&#xff1a;彩色图像分割首先涉及到像素级的特征提取。在彩色图像中&#xff0c;常用的特征包括颜色、纹理和…

用大模型训练实体机器人,谷歌推出机器人代理模型

谷歌DeepMind的研究人员推出了一款&#xff0c;通过视觉语言模型进行场景理解&#xff0c;并使用大语言模型来发出指令控制实体机器人的模型——AutoRT AutoRT可有效地推理自主权和安全性&#xff0c;并扩大实体机器人学习的数据收集规模。在实验中&#xff0c;AutoRT指导超过…
最新文章