Harmonny os——《从 TypeScript 到 ArkTS 的适配规则》精简笔记

《从 TypeScript 到 ArkTS 的适配规则》精简笔记

这一篇可以当成:"TS 项目迁到 ArkTS 时,哪些特性不能用 / 要怎么改" 的速查表

大原则:ArkTS = 强类型 + 固定对象布局 + 简化类型系统 + 编译期检查更严格


0. 总体原则 & 心态

约束级别

  • 错误(Error):必须改,不改就编译失败。
  • 警告(Warning):现在还能过,将来可能变成错误;能改则尽量改。

不再鼓励的两大类特性

  1. 动态类型 & 动态对象布局
    • any / unknown、动态加属性、删属性、原型操作、for..inindelete 等都被限制。
  2. 编译器负担重 / 容易写出"类型体操"的特性
    • 条件类型、映射类型、泛型 infer、structural typing、大部分 utility types、JSX、UMD 等。

1. 强制静态类型:any / unknown 彻底禁用

1.1 禁止 any / unknown

ts 复制代码
// ❌ ArkTS 不支持
let value1: any;
let value2: unknown;

要么写具体类型,要么用 Object

复制代码
// ✅ ArkTS
let valueB: boolean = true;
let valueN: number = 42;

let valueO1: Object = true;
let valueO2: Object = 42;

结论:见到 any / unknown → 一定要替换成具体类型 (或者顶多 Object)。

1.2 禁止关闭类型检查

  • 不支持:// @ts-ignore// @ts-nocheck
  • 严格模式永远开启:
    • strictNullChecks

    • strictPropertyInitialization

    • noImplicitReturns

    • strictFunctionTypes

      // ArkTS
      let s1: string | null = null; // 合法
      let s2: string = null; // ❌ 编译错误


2. 对象布局固定:不能动态改 Class 的"形状"

2.1 不能添加 / 删除属性(即使用 any)

复制代码
class Point {
  x: number = 0;
  y: number = 0;
}

let p = new Point();

// ❌ 删除属性
delete (p as any).x;

// ❌ 运行时新增属性
(p as any).z = 'label';

ArkTS:类一旦定义完,实例的字段集合就固定,不能在运行时"变胖变瘦"。

2.2 禁止 Symbol() API(除 Symbol.iterator

复制代码
// ❌ ArkTS 不支持自定义 Symbol
let prop = Symbol();
(p as any)[prop] = 1;

3. 限制运算符 & 语法特性

3.1 一元运算符 + - ~ 只允许数值

复制代码
let a = +5;   // ✅
let b = +'5'; // ❌ ArkTS 编译错误
let c = -'5'; // ❌
let d = ~'5'; // ❌

以前 TS 里很多"隐式字符串转 number"写法,在 ArkTS 全都不行。

3.2 禁止 delete / in / for..in

复制代码
// ❌ delete
class Point { x: number | null = 0; y: number | null = 0; }
let p = new Point();
p.y = null; // 用 null 表示"无值"

// ❌ in
let b = 'name' in p; // ArkTS 不支持

// ❌ for..in
let arr: string[] = ['1', '2'];
for (let i = 0; i < arr.length; ++i) {
  console.info(arr[i]);
}

3.3 不支持解构:包含 解构赋值 / 解构声明 / 参数解构

复制代码
// ❌ ArkTS 不支持
let [one, two] = [1, 2];

let { x, y } = returnZeroPoint();

function drawText({ text, location: [x, y], bold }: {...}) {}

ArkTS 写法:

复制代码
let arr: number[] = [1, 2];
let one = arr[0];
let two = arr[1];

let zp = returnZeroPoint();
let x = zp.x;
let y = zp.y;

function drawText(text: string, location: number[], bold: boolean) {
  let x = location[0];
  let y = location[1];
}

3.4 逗号运算符 , 只允许在 for 里用

复制代码
for (let i = 0, j = 0; i < 10; ++i, j += 2) {
  // ✅ 唯一合法场景
}

// ❌ 这样的写法不允许:x = (++x, x++);
let x = 0;
++x;
x = x++;

4. 类型系统:简化 + 明确(很多 TS 高级类型不能用)

4.1 不支持 structural typing(结构类型)

  • TS:只要 public API 一样,就可以互相赋值

  • ArkTS:必须有显式关系(继承、implements、类型别名)。

    // ✅ ArkTS 推荐:用 interface 抽出共同结构
    interface Z { n: number; s: string; }

    class X implements Z { n: number = 0; s: string = ''; }
    class Y implements Z { n: number = 0; s: string = ''; }

    let x: Z = new X();
    let y: Z = new Y();
    x = y;
    y = x;

4.2 不支持的类型特性(要整体有个印象)

  • ❌ 条件类型:T extends U ? X : Y
  • infer
  • ❌ 映射类型:{ [K in keyof T]: ... }
  • ❌ 大部分 Utility Types:
    只保留:Partial<T>, Required<T>, Readonly<T>, Record<K, T>
  • ❌ intersection types:A & B(用 extends 继承多个接口代替)
  • ❌ index signature:[key: string]: ...
  • ❌ 索引访问类型:T[K]
  • this 类型
  • typeof someVar 用作类型(表达式中 typeof 还可以)
  • ❌ 字面量类型 + as const
  • ❌ JSX
  • ❌ 生成器函数 function*
  • is 类型守卫(用 instanceof + as

可以直接记一句:TS 那些"玩类型体操"的高级类型,大部分 ArkTS 都禁止


5. 类 / 接口相关规则

5.1 不支持 #private,用 private 关键字

复制代码
// ❌ TS 写法
class C {
  #foo: number = 42;
}

// ✅ ArkTS
class C {
  private foo: number = 42;
}

5.2 构造函数中不能"顺便声明属性"

复制代码
// ❌ TS 写法
class Person {
  constructor(private name: string, private age: number) {}
}

// ✅ ArkTS
class Person {
  private name: string;
  private age: number;

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

5.3 类 & 接口的继承/实现限制

  • 接口 不能 继承类(只能继承其他接口)。

  • 不能implements

    复制代码
    // ❌ ArkTS
    class C { foo() {} }
    class C1 implements C { foo() {} }
    
    // ✅ 改成接口
    interface C { foo(): void; }
    class C1 implements C { foo() {} }
  • 接口不能继承两个里面有 同名方法 的接口(否则方法签名冲突)。

  • 不支持声明合并:class / interface / enum 不能写多次 partial 拼起来。

5.4 静态块:一个类里只能有一个 static 块

复制代码
class C {
  static s: string;

  static {
    C.s = 'aa';
    C.s = C.s + 'bb';
  }
}

6. 对象 / 数组字面量的规则

6.1 对象字面量必须有显式类型

复制代码
// ❌ ArkTS 不允许这样"裸字面量"
let o1 = { n: 42, s: 'foo' };

// ✅ ArkTS:显式类型
class C1 { n: number = 0; s: string = ''; }

let o1: C1 = { n: 42, s: 'foo' };
let oo: C1[] = [{ n: 1, s: '1' }, { n: 2, s: '2' }];

6.2 对象字面量不能当"匿名类型声明"

复制代码
// ❌ ArkTS
let o: { x: number; y: number } = { x: 2, y: 3 };

// ✅ 用 class / interface
class O { x: number = 0; y: number = 0; }
let o: O = { x: 2, y: 3 };

6.3 数组字面量:元素类型必须可推断

复制代码
class C { n: number = 0; s: string = ''; }

// ✅ 两种写法
let a1 = [{ n: 1, s: '1' } as C, { n: 2, s: '2' } as C]; // C[]
let a2: C[] = [{ n: 1, s: '1' }, { n: 2, s: '2' }];      // C[]

6.4 不能通过 obj['field'] 访问类字段

复制代码
class Person {
  name: string;
  age: number;
  email: string;
  phoneNumber: string;
  constructor(name: string, age: number, email: string, phoneNumber: string) {
    this.name = name;
    this.age = age;
    this.email = email;
    this.phoneNumber = phoneNumber;
  }
}

let p = new Person('John', 30, '***', '18***');

// ❌
console.info(p['name']);
console.info(p['unknownProperty']);

// ✅
console.info(p.name);

7. 函数相关:声明方式 / this / 返回类型

7.1 不支持函数表达式 & 嵌套函数声明

复制代码
// ❌ 函数表达式
let f = function (s: string) {
  console.info(s);
};

// ✅ 用箭头函数
let f = (s: string) => {
  console.info(s);
};
// ❌ 函数内声明函数
function addNum(a: number, b: number): void {
  function logToConsole(message: string): void {
    console.info(message);
  }
}

// ✅ 用 lambda
function addNum(a: number, b: number): void {
  let logToConsole = (message: string): void => {
    console.info(message);
  };
}

7.2 this 的使用限制

  • this 只能出现在类的实例方法里
  • ❌ 函数体 / 静态方法 / 自由函数中不能用 this。
  • 不支持 Function.apply / call / bind(这些都是动态改 this 的)。

7.3 返回类型推断:有些场景必须显式标注

复制代码
// ❌ ArkTS 要求加返回类型
function f(x: number) {         // 必须写: number
  if (x <= 0) return x;
  return g(x);
}

// ✅
function f(x: number): number {
  if (x <= 0) return x;
  return g(x);
}

function g(x: number): number { // 这里可以省略返回类型
  return f(x - 1);
}

8. 模块系统与 import / export 限制

  1. import 必须写在文件最前面 (除了动态 import())。

    复制代码
    // ✅
    import foo from 'module1';
    class C {}
  2. 不支持:

    • require
    • import = require('mod')
    • export = ...
    • ambient module 声明(declare module 'xxx' {}
    • 模块名通配符(declare module '*!text'
    • UMD 写法(export as namespace
  3. .ets 可以 import .ets/.ts/.js,但 .ts/.js 不能 import .ets


9. 标准库限制 & ESObject 使用收紧

9.1 禁止 / 限制的标准库 API

  • 全局:eval
  • Object 的一堆与原型 / 属性描述 / 动态扩展相关的 API 禁用,例如:
    • __proto__createdefinePropertysetPrototypeOf 等。
  • ReflectProxy 里面绝大部分也是禁用的。

9.2 ESObject:只能在"跨语言场景"慎用

  • 主要场景:动态导入、和 .ts/.js 的 any/unknown 对象打交道。
  • 不能随便用对象字面量初始化 ESObject
  • 允许点 / 下标访问、调用等,但会有较强限制。

10. 其他零碎但常考的点(记几个关键词)

  • let 而不是 var
  • 不支持 globalThis
  • 不支持 new.target
  • throw 只能抛出 Error 或其子类
  • 不支持 with
  • 不支持 JSX
  • 不支持 generator(用 async/await)
  • 命名空间里不能写可执行语句,只能声明;逻辑放到函数中,再调用。

11. 实战迁移小攻略(你写代码时可以这么用)

  1. 先全局搜索
    • any, unknown, as const, is (类型守卫), infer, keyof, in, for (let ... in, [key: 这种 index signature.
  2. 对类做一轮"ArkTS 检查"
    • 构造函数里有没有"顺带声明字段"的写法;
    • 有没有 #private
    • 有没有多个 static {}
    • 接口/类有没有声明合并、多次声明。
  3. 对函数做一轮
    • 是否有函数表达式 / 嵌套函数;
    • 参数有无解构;
    • 返回类型哪里是依赖其他调用推断的,要不要手写。
  4. 对对象/数组字面量做一轮
    • 对象字面量有没有显式类型;
    • 有没有 {x: number, y: number} 这种匿名类型;
    • 数组元素类型能不能直接推断成统一类型。
  5. 遇到拿不准的高级类型写法(复杂 type/utility)
    • 直接考虑:能不能改成 class + interface + 继承;
    • 优先追求"简单、直白、可读",而不是"类型体操"。
相关推荐
by__csdn1 小时前
Vue 中计算属性、监听属性与函数方法的区别详解
前端·javascript·vue.js·typescript·vue·css3·html5
Ccjf酷儿1 小时前
操作系统 李治军 1 操作系统基础
笔记
Ghost-Silver1 小时前
《星火》——关于Deepseek的进化速度
笔记·算法
古译汉书1 小时前
嵌入式笔记(个人总结)
数据结构·笔记·stm32·单片机·嵌入式硬件
IT从业者张某某1 小时前
DAY1-Open Harmony PC 命令行适配指南(Windows版)环境准备篇
harmonyos·鸿蒙
雍凉明月夜1 小时前
视觉opencv学习笔记Ⅲ
笔记·opencv·学习
赵财猫._.2 小时前
HarmonyOS渲染性能优化:组件树复用与局部刷新机制
wpf·harmonyos·ux
赵财猫._.2 小时前
鸿蒙分布式数据库同步:冲突解决与数据一致性策略
wpf·harmonyos·ux
客梦2 小时前
Java 道路信息系统
java·笔记