ArkTS1.2互操作概述

背景

ArkTS1.2在ArkTS1.1版本的基础上增强了类型安全和并发能力,带来了基于静态类型系统的编译器和运行时实现。为了让开发者能够达到更好的并发性能等目的,可选择ArkTS1.2作为开发语言,或将存量应用逐步改造为ArkTS1.2版本。在此场景下,为了让开发者能够复用已有的生态资产,以及让存量应用的开发者可以便捷地逐步迁移到ArkTS1.2,我们需要提供ArkTS1.2和ArkTS1.1以及TS/JS代码的交互能力。

可交互方向

  • ArkTS1.2可以导入ArkTS1.1, TS, JS。
  • ArkTS1.1可以导入ArkTS1.2。
  • TS/JS不可以导入ArkTS1.2/ArkTS1.1。

ArkTS1.2 静态语义原则

  • ArkTS1.2的对象的布局不能被修改,动态修改对象布局(包括新增或删除对象属性,以及修改对象属性的类型)将会出现编译时报错或者运行时报错。
  • ArkTS1.2的函数参数需要匹配声明的类型,否则会出现编译报错或运行时报错。
  • ArkTS1.2代码中的类型转换如果不能在运行时以合理的方式进行,将会出现编译报错或运行时报错。

ArkTS1.2类型系统

  • ArkTS1.2的顶层类型有:undefinednullAny
    • Any有子类ObjectObject有子类ESValue。ArkTS1.2中的自定义类,标准库(Array/Map/Set等)等类型都是Object的子类型。

ESValue

  • ESValueObject的子类。
  • ESValue可用于封装来自于JS的对象。
  • ESValue提供了多种方法来对应对象的常见操作。比如:加载 JS 模块、实例化new obj(x)、函数调用obj(x)、属性访问obj.prop、方法调用obj.foo(x)、索引访问obj[idx]等。
  • ArkTS1.2的ESValue作为普通的类型,并无额外限制和额外特权。比如:ArkTS1.2中ESValue可以用于类型标注和泛型,但针对ESValue类型对象的操作也只能通过调用它的方法来进行。
AnyObject
    |
Object
    |
ESValue  -|- (static) load(path: string): ESValue                            // 模块加载
          |- wrap(arg: Any)                                                  // 将对象包装成ESValue实例
          |- getProperty(key: string | number): ESValue                      // 读属性
          |- setProperty(key: string | number, newVal: ESValue): void        // 写属性
          |- instantiate(...args: ESValue[]): ESValue                        // 实例化
          |- invoke(...args: ESValue[]): ESValue                             // 函数调用
          |- invokeMethod(methodName: string, ...args: ESValue[]): ESValue   // 方法调用
          |- toString(): string                                              // 将包装的对象转换为string
          |- toNumber(): number                                              // 将包装的对象转换为number
          |- ...

(TODO:加链接)ESValue接口说明文档。

交互基本原则

  • ArkTS1.2特有的语言特性不能用于和ArkTS1.1交互(比如:重载、注解、final、尾随闭包、function with receiver)。
  • ArkTS1.0特有的语言特性不能用于和ArkTS1.2交互(比如:@Sendable/@Concurrenct)。
  • TS特有的语言特性不能用于和ArkTS1.2交互(比如:decorator、call-signature)。
  • ArkTS1.2的对象属性在动态上下文使用时有如下特点:
    • 没有自身属性(own property)。
    • 对象和对象的属性都是密封的(sealed)。
  • ArkTS1.2和JS的交互,需要开发者显式调用API来进行交互。
// file1.js
export class A {
  constructor() {
    console.log("new A");
  }
  msg = "hello";
  data = [1, 2, 3];
  say(arg) {
    console.log(this.msg + arg);
  }
}
export function foo(arg) {
  return arg;
}
// file2.ets ArkTS1.2
'use static'
// 加载模块
let module: ESValue = ESValue.load('./file1')
let foo: ESValue = module.getProperty('foo')
let A: ESValue = module.getProperty('A')
// 实例化
let aa: ESValue = A.instantiate()
// 调用函数
let a: ESValue = foo.invoke(aa)
// 读属性
let msg: ESValue = a.getProperty('msg')
let msgStr: string = msg.toString()  // 'hello'
let data: ESValue = a.getProperty('data')
// 写属性
let newMsgValue: ESValue = ESValue.wrap('world')  // 将对象包装成ESValue实例
a.setProperty('msg', newMsgValue)
// 调用方法
a.invokeMethod('say', ESValue.wrap(' cup'))  // 打印'world cup'
// 读索引元素
let element0 = data.getProperty(0)
element0.toNumber()  // 1
// 写索引元素
data.setProperty(2, ESValue.wrap(4))
  • ArkTS1.2和ArkTS1.1/TS的交互,不需要开发者显式调用API来进行交互。
// file1.ts
export class A {
  constructor() {
    console.log("new A");
  }
  msg: string = "hello";
  data: Array<number> = [1, 2, 3];
  say(arg: string): void {
    console.log(this.msg + arg);
  }
}
export function foo(arg: A): A {
  return arg;
}
// file2.ets ArkTS1.2
'use static'
// 加载模块
import { A, foo } from "./file1";
// 实例化
let aa: A = new A();
// 调用函数
let a: A = foo(aa);
// 读属性
let msg: string = a.msg; // 'hello'
let data: Array<number> = a.data;
// 写属性
a.msg = "world";
// 调用方法
a.say(" cup"); // 打印'world cup'
// 读索引元素
let element0 = data[0]; // 1
// 写索引元素
data[2] = 4;