欢迎光临
我们一直在努力

鸿蒙开发入门指南:从前端TypeScript到ArkTS过渡指南

鸿蒙开发入门指南:从前端TypeScript到ArkTS过渡指南

    • 一、先理解最核心的一句话
    • 二、为什么要从TS迁移到ArkTS?
      • 2.1 程序稳定性:把错误扼杀在编译阶段
      • 2.2 程序性能:减少运行时的类型检查
    • 三、迁移核心:从“能用”到“规范”
      • 3.1 最需要改的10条规则(新手必看)
        • 规则1:使用let,别用var(arkts-no-var)
        • 规则2:别用any和unknown(arkts-no-any-unknown)
        • 规则3:类的属性必须初始化(编译强制)
        • 规则4:构造函数里不能声明字段(arkts-no-ctor-prop-decls)
        • 规则5:用箭头函数,别用函数表达式(arkts-no-func-expressions)
        • 规则6:用点访问属性,别用方括号(arkts-no-props-by-index)
        • 规则7:类型转换用as,别用尖括号(arkts-as-casts)
        • 规则8:别用解构赋值(arkts-no-destruct-assignment)
        • 规则9:别用for…in,用普通for循环(arkts-no-for-in)
        • 规则10:throw只能抛Error对象(arkts-limited-throw)
    • 四、进阶迁移:这些特性ArkTS不支持
      • 4.1 不支持动态修改对象
      • 4.2 不支持structural typing
      • 4.3 不支持运算符重载
      • 4.4 不支持解构声明
    • 五、迁移实战:一个真实案例
      • TS原版代码
      • ArkTS迁移后
    • 六、兼容性说明:版本差异要注意
      • 6.1 根据SDK版本的不同
      • 6.2 文件引用规则
    • 七、迁移清单:照着这个改就行
      • 必改项(编译错误)
      • 建议改(警告)
    • 八、总结:一张表记住TS和ArkTS的核心差异
  • 结语:写给正在迁移代码的你

大家好,我是木斯佳。

很多从前端转鸿蒙的朋友,第一次接触ArkTS时都会有这样的疑惑: 在这里插入图片描述

“这不就是TypeScript吗?为什么我的TS代码复制进去就报错?” “ArkTS到底改了啥?我写了这么多年的TS,现在要重新学?”

别慌。今天这篇文章,我就用跨端开发者的视角,帮你彻底理清从TS到ArkTS的过渡容易坑的点。文章有点长,但保证你看完就能懂,懂了就能改。


一、先理解最核心的一句话

ArkTS = TypeScript – 动态特性 + 更严格的静态检查

就这么简单。

ArkTS保留了TS的大部分语法,但砍掉了一些影响性能和稳定性的动态特性,同时加强了编译时的类型检查。这么做的目的是什么?

  • 程序更稳定:运行时少报错
  • 性能更好:减少运行时的类型检查
  • 代码更清晰:类型一目了然

说白了,就是用开发时的“麻烦”换运行时的“顺畅”。


二、为什么要从TS迁移到ArkTS?

一部分是像我这种前端开发,编程习惯导致很多时候肌肉记忆写出来的代码在鸿蒙编译不通过。 另外在工程化上,我们有很多web三方的utils库是非常经典的,在造轮子的过程中,不可避免的会从一个范式到另一个范式的迁移过渡。

2.1 程序稳定性:把错误扼杀在编译阶段

动态类型语言(比如JavaScript)虽然开发爽,但运行时容易翻车。最典型的就是undefined错误:

// TypeScript(非严格模式)
class Person {
name: string; // 没初始化,实际是undefined

getName(): string {
return this.name; // 返回类型写string,但实际可能是undefined
}
}

let buddy = new Person();
buddy.getName().length; // 运行时崩溃:name is undefined

这个问题在TS里可能被忽略,但在ArkTS里根本编译不过:

// ArkTS
class Person {
name: string = ''; // 必须显式初始化

getName(): string {
return this.name; // 现在保证是string,不会是undefined
}
}

let buddy = new Person();
buddy.getName().length; // 0,安全运行

如果name真的可能为空,那就得明确写出来:

class Person {
name?: string; // 可能为undefined

getName(): string | undefined { // 返回类型也要匹配
return this.name;
}
}

buddy.getName()?.length; // 必须用可选链,否则编译报错

2.2 程序性能:减少运行时的类型检查

JavaScript引擎为了处理动态类型,需要在运行时做大量检查。比如这个简单的函数:

function notify(who: string, what: string) {
console.info(`Dear ${who}, a message for you: ${what}`);
}

在JS里,如果有人调用notify(null, undefined),引擎就得做类似这样的检查:

function __internal_tostring(s) {
if (typeof s === 'string') return s;
if (s === undefined) return 'undefined';
if (s === null) return 'null';
// …
}

ArkTS通过强制静态类型,保证运行时不会出现非string类型的值,这些检查就可以省略,性能自然就上去了。


三、迁移核心:从“能用”到“规范”

3.1 最需要改的10条规则(新手必看)

下面是我总结的、迁移中最常遇到的10条规则,看完就能上手改代码。

规则1:使用let,别用var(arkts-no-var)

错误:

var x = 10;

正确:

let x = 10;

规则2:别用any和unknown(arkts-no-any-unknown)

错误:

let value: any = 'hello';
value = 42; // 随便改类型

正确:

let value: string = 'hello'; // 明确类型
// 或者如果真的需要多种类型
let value2: string | number = 'hello';
value2 = 42; // 合法

规则3:类的属性必须初始化(编译强制)

错误:

class Person {
name: string; // 没初始化
age: number; // 没初始化
}

正确:

class Person {
name: string = '';
age: number = 0;
// 或者在构造函数里初始化
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}

规则4:构造函数里不能声明字段(arkts-no-ctor-prop-decls)

错误(TS的简写语法):

class Person {
constructor(
private name: string, // 直接在参数里声明字段
public age: number
) {}
}

正确:

class Person {
private name: string;
public age: number;

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

规则5:用箭头函数,别用函数表达式(arkts-no-func-expressions)

错误:

let f = function(s: string) {
console.info(s);
}

正确:

let f = (s: string) => {
console.info(s);
}

规则6:用点访问属性,别用方括号(arkts-no-props-by-index)

错误:

let obj = { name: 'John' };
console.info(obj['name']); // 索引访问

正确:

let obj = { name: 'John' };
console.info(obj.name); // 点访问

规则7:类型转换用as,别用尖括号(arkts-as-casts)

错误:

let value = <string>someVar; // TS风格

正确:

let value = someVar as string; // ArkTS风格

规则8:别用解构赋值(arkts-no-destruct-assignment)

错误:

let [a, b] = [1, 2];
[a, b] = [b, a]; // 交换变量

正确:

let arr = [1, 2];
let a = arr[0];
let b = arr[1];

let tmp = a;
a = b;
b = tmp;

规则9:别用for…in,用普通for循环(arkts-no-for-in)

错误:

let arr = ['a', 'b', 'c'];
for (let i in arr) {
console.info(arr[i]);
}

正确:

let arr = ['a', 'b', 'c'];
for (let i = 0; i < arr.length; i++) {
console.info(arr[i]);
}
// 或者用for…of(支持)
for (let item of arr) {
console.info(item);
}

规则10:throw只能抛Error对象(arkts-limited-throw)

错误:

throw '出错了'; // 抛字符串
throw 404; // 抛数字

正确:

throw new Error('出错了');


四、进阶迁移:这些特性ArkTS不支持

4.1 不支持动态修改对象

在ArkTS里,对象的布局是固定的,不能在运行时添加或删除属性。

class Point {
x: number = 0;
y: number = 0;
}

let p = new Point();

// 以下操作都不允许
delete p.x; // 编译错误
p.z = 10; // 编译错误
(p as any).z = 10; // 编译错误(不能用any绕过)

怎么改:在设计类的时候就把所有可能的属性都定义好。

4.2 不支持structural typing

在TS里,只要两个类结构一样,就可以互相赋值:

// TypeScript
class T {
name: string = '';
greet() { console.info('Hello'); }
}

class U {
name: string = '';
greet() { console.info('Greetings'); }
}

let u: U = new T(); // TS里合法,结构相同

ArkTS不支持这个,必须通过继承或实现接口来建立关系:

// ArkTS
interface Greetable {
name: string;
greet(): void;
}

class T implements Greetable {
name: string = '';
greet() { console.info('Hello'); }
}

class U implements Greetable {
name: string = '';
greet() { console.info('Greetings'); }
}

let u: Greetable = new T(); // 合法,都实现了相同接口

4.3 不支持运算符重载

ArkTS对一元运算符有严格限制,只能用于数值类型:

let a = +5; // 合法
let b = +'5'; // 编译错误,不能把字符串转数值
let c = '5'; // 编译错误

// 需要显式转换
let d = Number('5'); // 正确做法

4.4 不支持解构声明

// 错误
let {x, y} = point;

// 正确
let x = point.x;
let y = point.y;


五、迁移实战:一个真实案例

假设我们有一个TS写的工具类,看看怎么迁移到ArkTS。

TS原版代码

在这里插入图片描述

// utils.ts
class Logger {
level: string; // 没初始化

constructor(level?: string) {
if (level) {
this.level = level;
}
}

log(message: string) {
console[this.level](message); // 可能报错
}
}

// 使用
let logger = new Logger();
logger.log('hello'); // 运行时崩溃:this.level是undefined

ArkTS迁移后

在这里插入图片描述

// utils.ets
class Logger {
level: string = 'log'; // 给个默认值

constructor(level?: string) {
if (level) {
this.level = level;
}
}

log(message: string) {
// 安全访问
if (this.level ) {

} else {
console.log(message);
}
}
}

// 使用
let logger = new Logger();
logger.log('hello'); // 安全运行


六、兼容性说明:版本差异要注意

6.1 根据SDK版本的不同

compatibleSdkVersion模式行为
>= 10 标准模式 必须严格遵循ArkTS语法,否则编译失败
< 10 兼容模式 违反规则只给警告,仍可编译成功

建议:新项目直接上标准模式,老项目逐步迁移。

6.2 文件引用规则

  • ✅ .ets文件可以import .ets/.ts/.js文件
  • ❌ .ts/.js文件不能import .ets文件

这意味着核心逻辑最好写在.ets文件里,避免循环依赖。


七、迁移清单:照着这个改就行

必改项(编译错误)

  • 把var改成let
  • 去掉所有any和unknown
  • 类的属性必须初始化
  • 构造函数参数里不能声明字段
  • 函数表达式改成箭头函数
  • 属性访问用点,别用方括号
  • 类型转换用as,别用尖括号
  • 去掉解构赋值
  • for…in改成for循环或for…of
  • throw只能抛Error对象

建议改(警告)

  • 不要用Function.bind/call/apply
  • 不要用globalThis
  • 不要用as const
  • 不要用@ts-ignore(ArkTS里直接报错)

八、总结:一张表记住TS和ArkTS的核心差异

特性TypeScriptArkTS迁移建议
类型系统 渐进式 强制静态 所有变量都要有明确类型
any类型 支持 ❌ 不支持 用具体类型或联合类型替代
属性初始化 可选 必须 声明时就初始化或在构造函数里初始化
解构赋值 支持 ❌ 不支持 拆开写
for…in 支持 ❌ 不支持 用for或for…of
对象动态属性 支持 ❌ 不支持 类里预先定义好所有属性
throw类型 任意 只能是Error throw new Error()
this使用 任意位置 仅限于实例方法 静态方法和函数里不能用this
文件引用 任意 .ets不能被子.ts引用 核心逻辑写在.ets

结语:写给正在迁移代码的你

写完这篇迁移指南,我想和你聊几句心里话。

说实话,刚接触ArkTS的时候,我也觉得挺烦的——明明TS写得好好的,为什么要改?明明any多方便,为什么不让用?

但真正把代码迁移过来之后,我才理解了这个设计的良苦用心。

你发现没有?ArkTS砍掉的这些特性,恰恰是我们在TS里最容易踩坑的地方:

  • any一时爽,重构火葬场
  • 属性不初始化,运行时undefined报错
  • 解构赋值看起来很酷,但类型推导经常出问题
  • 动态添加属性,代码越写越乱

ArkTS的做法,相当于帮你把“可以偷懒但容易翻车”的路都堵上了。刚开始会觉得不习惯,但写久了你会发现:代码更稳了,bug更少了,团队协作也更顺畅了。

迁移的过程,其实就是从“能用”走向“规范”的过程。

刚开始可能会慢一点,但每改一个any,每初始化一个属性,你都在为自己的代码增加一分稳定性,为未来的自己减少一个debug的夜晚。

  • 从新模块开始:别想着一次性迁移整个项目,新写的代码直接用ArkTS规范,老代码逐步改造

  • 用好编译错误:ArkTS的编译器很严格,但它报的错都是为你好的。每修复一个错误,就少了一个潜在的运行时bug

  • 保持学习心态:刚开始会觉得约束太多,但慢慢你会发现,这些约束其实是在帮你建立更好的编码习惯

  • 遇到问题多思考:不要简单地“把报错改掉”,而是理解为什么报错,ArkTS想让你怎么写更好

  • 技术这条路很长,从一个框架到另一个框架,从一种范式到另一种范式,每一次迁移都是一次成长。 在这里插入图片描述

    我是木斯佳,希望这篇指南能帮你在鸿蒙的世界里少踩几个坑。下篇见。

    赞(0)
    未经允许不得转载:171主机测评 » 鸿蒙开发入门指南:从前端TypeScript到ArkTS过渡指南
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址