ArkTS1.2互操作特性规范

ArkTS1.2互操作场景

ArkTS1.1中使用ArkTS1.2

文件导入

在ArkTS1.2中使用import函数导入ArkTS1.1的文件相关的内容,包含函数,类,对象等。

// file1.ets ArkTS1.2
'use static'
export function func(){}
export class A{}
export let a: A = new A();

// file2.ets ArkTS1.1
import { func, A, a} from './file1'

类实例化

在ArkTS1.1中可以使用从ArkTS1.2中导入的类,用new来创建该类的实例。

// file1.ets ArkTS1.2
'use static'
export class A {}
export class B extends A {}
interface interA {}
export class C implements interA {}

// file2.ets ArkTS1.1
import { A, B, C } from "file1";
let a = new A();
let b = new B();
let c = new C();

属性读写

在ArkTS1.1中可以读写ArkTS1.2中导入的对象的属性。

// file1.ets ArkTS1.2
'use static'
export class Person {
  name: string = "unknown"
}

// file2.ets ArkTS1.1
import { Person } from "file1";
let a = new Person();
let b = a.name; // "unknown"
a.name = "John";

函数调用

在ArkTS1.1中可以直接调用ArkTS1.2中导入的函数。

// file1.ets ArkTS1.2
'use static'
export let func = () => {
  console.log("123");
};
export function foo1() {}
export function foo2(a: number, b: number): number {
  return a + b;
}

// file2.ets ArkTS1.1
import { func, foo1, foo2 } from "file1";
func();
foo1();
foo2(1.5, 2.5);

对象方法调用

在ArkTS1.2中可以直接访问ArkTS1.1导入对象的方法。

// file1.ets ArkTS1.2
'use static'
export class A {
  log() {
    console.log("123")
  }
}
class B {
  foo() : void {}
}
export class C extends B {
  override foo() : void { console.log('D.foo') }
}
interface InterA {
  foo: () => void;
}
export let itA: InterA = {
  foo: () => { console.log('interface log') }
}
export let arr = new Array<number>(1, 2, 3);

// file2.ets ArkTS1.1
import { A, C, itA, arr } from 'file1'
let a = new A()
a.log()
let c = new C()
c.foo()  // Output: D.foo
itA.foo()
arr.push(4)

参数传递

在ArkTS1.1中可以将ArkTS1.1的参数传至导入的函数,从而回传至ArkTS1.2。

// file1.ets ArkTS1.2
'use static'
export function foo(a: Array<string>) {
  console.log(a[0]);
}
export class C {
  static foo(a: Array<string>) {
    console.log(a[0]);
  }
  bar(a: Array<string>) {
    console.log(a[0]);
  }
}
export interface Iface {
  foo(a: Array<string>): void;
}

// file2.ets ArkTS1.1
import { foo, C, Iface } from "file1";

foo(["Hi", "Bye"]); // Output: Hi
C.foo(["Hi", "Bye"]); // Output: Hi
new C().bar(["Hi", "Bye"]); // Output: Hi

function baz(i: Iface) {
  i.foo(["Hi", "Bye"]); // OK
}

异常处理

ArkTS1.1中定义一个异常的实例,可以在ArkTS1.2中捕获这个异常。

// file1.ets ArkTS1.2
'use static'
export function foo() {
  throw new Error("123");
}

// file2.ets ArkTS1.1
import { foo } from "1.1";

try {
  foo();
} catch (e) {
  (e as Error).message; // "123"
}

ArkTS1.2中使用TS

文件导入

在ArkTS1.2中使用import函数导入ArkTS1.1的文件相关的内容,包含函数,类,对象等。

// file1.ts
export function func(){}
export class A{}
export let a: A = new A();

// file2.ets ArkTS1.2
'use static'
import { func, A, a} from './file1'

类实例化

在ArkTS1.1中可以使用从ArkTS1.2中导入的类,用new来创建该类的实例。可以访问实例的方法和属性。也可以使用ArkTS1.1的类扩展ArkTS1.2的类后创建实例对象。

// file1.ts
export class A {}
export class B extends A {}
interface interA {}
export class C implements interA {}

// file2.ets ArkTS1.2
'use static'
import { A, B, C } from "file1";
let a = new A();
let b = new B();
let c = new C();

属性读写

在ArkTS1.2中可以读写从TS中导入对象。

// file1.ts
export class Person {
  name: string = "unknown"
}

// file2.ets ArkTS1.2
'use static'
import { Person } from "file1";
let a = new Person();
let b = a.name; // "unknown"
a.name = "John";

函数调用

在ArkTS1.2中可以调用从TS中导入函数。

// file1.ts
export let func = () => {
  console.log("123");
};
export function foo1() {}
export function foo2(a: number, b: number): number {
  return a + b;
}

// file2.ets ArkTS1.2
'use static'
import { func, foo1, foo2 } from "file1";
func();
foo1();
foo2(1.5, 2.5);

对象方法调用

在ArkTS1.2中可以调用从TS中导入的对象,并调用该对象的方法。

// file1.ts
export class A {
  log() {
    console.log("123")
  }
}
class B {
  foo() : void {}
}
export class C extends B {
  override foo() : void { console.log('D.foo') }
}
interface InterA {
  foo: () => void;
}
export let itA: InterA = {
  foo: () => { console.log('interface log')) }
}
export let arr = new Array<number>(1, 2, 3);

// file2.ets ArkTS1.2
'use static'
import { A, C, itA, arr } from 'file1'
let a = new A()
a.log()
let c = new C()
c.foo()  // Output: D.foo
itA.foo()
arr.push(4)

参数传递

在ArkTS1.2中可以调用从TS中导入的函数,并将参数传递至TS。

// file1.ts
export function foo(a: Array<string>) {
  console.log(a[0]);
}
export class C {
  static foo(a: Array<string>) {
    console.log(a[0]);
  }
  bar(a: Array<string>) {
    console.log(a[0]);
  }
}
export interface Iface {
  foo(a: Array<string>): void;
}

// file2.ets ArkTS1.2
'use static'
import { foo, C, Iface } from "file1";

foo(["Hi", "Bye"]); // Output: Hi
C.foo(["Hi", "Bye"]); // Output: Hi
new C().bar(["Hi", "Bye"]); // Output: Hi

function baz(i: Iface) {
  i.foo(["Hi", "Bye"]); // OK
}

异常处理

TS中定义一个异常的实例,可以在ArkTS1.2中捕获这个异常。

// file1.ts
export function foo() {
  throw new Error("123")
}

// file2.ets ArkTS1.2
'use static'
import { foo } from "./file1";

try {
  foo();
} catch (e) {
  (e as Error).message; // '123'
}

ArkTS1.2中使用JS

文件导入

// file1.js
export function func(){}
export class A{}
export let a: A = new A();

// file2.ets ArkTS1.2
'use static'
let mod: ESValue = ESValue.load('./file1')
let func: ESValue = mod.getProperty('func')
let A: ESValue = mod.getProperty('A')
let a: ESValue = mod.getProperty('a')

类实例化

可以在ArkTS1.2中创建新的JS类,通过ESValue创建JS类的实例。

// file1.js
export class A {}

// file2.ets ArkTS1.2
'use static'
let mod: ESValue = ESValue.load("./file1");
let A: ESValue = module.getProperty("A");
let a: ESValue = A.instantiate();  // 创建A的实例,这个实例被包装在a中

属性读写

在ArkTS1.2中可以访问JS类实例的字段和方法。

// file1.js
export class A {
  name = "unknown"
}

// file2.ets ArkTS1.2
'use static'
let module = ESValue.load('./file1')
let A = module.getProperty('A');
let a = A.instantiate()
b.getProperty('name').toString()  // "unknown"
a.setProperty('name', ESValue.wrap('John'))
b.getProperty('name').toString()  // "John"

函数调用

在ArkTS1.2中可以通过ESValue来调用JS的函数。

// file1.js
export function foo() {
    return 100
}

// file2.ets ArkTS1.2
'use static'
let foo: ESValue = ESValue.load("./file1").getProperty("foo");
let res: ESValue = foo.invoke();
let resNum: string = res.toNumber();  // 100

对象方法调用

在ArkTS1.2中可以通过ESValue来调用JS的对象的方法。

//file1.js
export class A {
  sayHi(msg: string) {
    console.log(msg)
    return msg
  }
  static getInstance() {
    return new A()
  }
}

//file2.ets  ArkTS1.2
'use static'
let A = ESValue.load('./file1').getProperty('A')
let a: ESValue = A.invokeMethod('getInstance')  // 调用静态方法
let msg: ESValue = a.invokeMethod('sayHi', ESValue.wrap('hello'))  // 调用实例方法, 打印hello
msg.toString()  // 'hello'

参数传递

在ArkTS1.2中可以通过ESValue来调用JS的函数将参数传递至JS。

// file1.js
export function foo(msg, count) {
  for (let i = 0; i < count; ++i) {
    console.log(msg)
  }
}

// file2.ets ArkTS1.2
'use static'
let foo = ESValue.load("./file1").getProperty("foo");
foo.invoke(ESValue.wrap("hello"), ESValue.wrap(3));  // 打印3次hello

异常处理

在JS中定义一个异常的实例,可以在ArkTS1.2中ESValue来获取这个异常。

// file1.js
export function foo() {
  throw new Error('123')
}

// file2.ets  ArkTS1.2
'use static'
let foo = ESValue.load('./file1').getProperty('foo')
try {
  foo.invoke()
} catch(e) {
  (e as Error).message  // '123'
}

交互限制

在ArkTS1.2中使用ArkTS1.1

ArkTS1.1给ArkTS1.2传参或赋值给Object类型

  • ArkTS1.1语法
// fiel1.ets
export function foo(obj: Object) {}
export class A {
  data: Object = 0;
}

// file2.ets
import { foo, A } from "./file1";

class X {}
foo(new X());
interface Y {
  s: string;
}
let y: Y = { s: "Hi" };
let a = new A();
a.data = y;
  • ArkTS1.2语法
// fiel1.ets ArkTS1.2
'use static'
export function foo(obj: Object) {}
// solution: export function foo(obj: Any) {}
export class A {
  data: Object = 0;
}
// solution: export class A { data: Any = ESValue.wrap(0) }

// file2.ets ArkTS1.1
import { foo, A } from "./file1";

class X {}
foo(new X()); // 运行时报错
interface Y {
  s: string;
}
let y: Y = { s: "Hi" };
let a = new A();
a.data = y; // 运行时报错
  • 编译报错信息: nan
  • 运行时报错信息: runtime type cast error
  • 适配建议: nan
  • 变更理由: nan

ArkTS1.1的Object内置方法作用在ArkTS1.2对象上

  • ArkTS1.1语法
// file2.ets
export class X {
  a = 1;
}

// file1.ets
import { X } from "./file2";
function foo(prx: Object) {
  Object.getOwnPropertyNames(prx); // ['a']
  Object.hasOwn(prx, "a"); // true
  Object.keys(prx); // ['a']
  Object.values(prx); // [1]
}

foo(new X());
  • ArkTS1.2语法
// file2.ets ArkTS1.2
'use static'
export class X {
  a = 1;
}
// solution for Object.keys, case for Object.values is similar:
export function getKeys(prx: Object | ESValue): string[] | undefined {
  if (prx instanceof Object) {
    return Object.keys(prx);
  }
  return undefined;
}
// file1.ets ArkTS1.1
import { X, getKeys } from "./file2";
function myGetKeys(prx: Object) {
  let ret = getKeys(prx);
  if (ret == undefined) {
    // prx is dynamic
    return Object.keys(prx);
  }
  return ret;
}
export function foo(prx: Object) {
  Object.getOwnPropertyNames(prx); // []
  Object.hasOwn(prx, "a"); // false
  Object.keys(prx); // []
  myGetKeys(prx); // ['a']
  Object.values(prx); // []
}

foo(new X());
  • 编译报错信息: nan
  • 运行时报错信息: object is sealed
  • 适配建议: nan
  • 变更理由: nan

ArkTS1.1的Reflect内置方法作用在ArkTS1.2对象上

  • ArkTS1.1语法
// file2.ets
export class X {
  a: string = "hello";
  getName() {
    return this.a;
  }
}

// file1.ets
import { X } from "./file2";
function foo(prx: Object) {
  Reflect.ownKeys(prx); // ['a']
  Reflect.set(prx, "newField", 7); // true
}

foo(new X());
  • ArkTS1.2语法
// file2.ets  ArkTS1.2
'use static'
export class X {
  a: string = 'hello'
  getName() { return this.a }
}

// solution for static ownKeys:
export getOwnKeys(prx: Object | ESValue): string[] | undefined {
  if (prx instanceof Object) { return Reflect.ownKeys(prx) }
  return undefined
}

// file1.ets ArkTS1.1
import {X, getOwnKeys} from './file2'
function myOwnKeys(prx: Object) {
  let ret = getOwnKeys(prx)
  if (ret == undefined) {  // prx is dynamic
    return Reflect.ownKeys(prx)
  }
  return ret
}

function foo(prx: Object) {
 Reflect.ownKeys(prx)  // []
 myOwnKeys(prx)  // ['a']
 Reflect.set(prx, 'newField', 7)  // false
}

foo(new X())
  • 编译报错信息: nan
  • 运行时报错信息: runtime cast error
  • 适配建议: nan
  • 变更理由: nan

ArkTS1.2的Object内置方法作用在ArkTS1.1对象上

  • ArkTS1.1语法
// file1.ets
export function foo(prx: Object) {
  Object.assign({}, prx); // OK
  Object.entries(prx); // [a, 1]
  Object.keys(prx); // ['a']
  Object.values(prx); // [1]
  prx.hasOwnProperty("a"); // true
}

// file2.ets
import { foo } from "./file1";
class X {
  a = 1;
}
foo(new X());
  • ArkTS1.2语法
// file1.ets  ArkTS1.2
'use static'
export function foo(prx: Object) {
  Object.assign({}, prx); // OK
  Object.entries(prx); // [a, 1]
  Object.keys(prx); // ['a']
  Object.values(prx); // [1]
  prx.hasOwnProperty("a"); // true
}

// file2.ets  ArkTS1.1
import { foo } from "./file1";
class X {
  a = 1;
}
foo(new X()); // 运行时报错
  • 编译报错信息: nan
  • 运行时报错信息: object is sealed
  • 适配建议: nan
  • 变更理由: nan

ArkTS1.2 Reflect内置方法作用在ArkTS1.1对象

  • ArkTS1.1语法
// file1.ets
export function foo(prx: Object) {
  Reflect.get(prx, "a"); // 'hello'
  Reflect.set(prx, "a", "world"); // true
  Reflect.ownKeys(prx); // ['a']
}

// file2.ets
import { foo } from "./file1";
class X {
  a: string = "hello";
  getName() {
    return this.a;
  }
}
foo(new X());
  • ArkTS1.2语法
// file1.ets  ArkTS1.2
'use static'
export function foo(prx: Object) {
  Reflect.get(prx, "a"); // 'hello'
  Reflect.set(prx, "a", "world"); // true
  Reflect.ownKeys(prx); // ['a']
}

// file2.ets  ArkTS1.1
import { foo } from "./file1";
class X {
  a: string = "hello";
  getName() {
    return this.a;
  }
}
foo(new X()); // 运行时报错
  • 编译报错信息: nan
  • 运行时报错信息: runtime cast error
  • 适配建议: nan
  • 变更理由: nan

ArkTS1.1中使用ArkTS1.2

ArkTS1.1 Object内置方法作用在ArkTS1.2对象

  • ArkTS1.1语法
// file1.ets
export function foo(prx: Object) {
  Object.getOwnPropertyNames(prx); // ['a']
  Object.hasOwn(prx, "a"); // true
  Object.keys(prx); // ['a']
  Object.values(prx); // [1]
}

// file2.ets
import { foo } from "./file1";
class X {
  a = 1;
}
foo(new X());
  • ArkTS1.2语法
// solution for Object.keys, case for Object.values is similar:
// file0.ets  ArkTS1.2
'use static'
export function getKeys(prx: Any): string[] | undefined {
  if (prx instanceof Object) {
    return Object.keys(prx);
  }
  return undefined;
}

// file1.ets ArkTS1.1
import { getKeys } from "./file0";
function myGetKeys(prx: Object) {
  let ret = getKeys(prx);
  if (ret == undefined) {
    // prx is dynamic
    return Object.keys(prx);
  }
  return ret;
}
export function foo(prx: Object) {
  Object.getOwnPropertyNames(prx); // []
  Object.hasOwn(prx, "a"); // false
  Object.keys(prx); // []
  myGetKeys(prx); // ["a"]
  Object.values(prx); // []
}

// file2.ets  ArkTS1.2
'use static'
import { foo } from "./file1";
class X {
  a = 1;
}
foo(new X());
  • 编译报错信息: nan
  • 运行时报错信息: object is sealed
  • 适配建议: 根据这些变化重新适配代码,或者避免使用这些内置底层接口。
  • 变更理由: ArkTS1.2对象在动态上下文中没有own property,表现为sealed,不能修改对象布局。

ArkTS1.1 Reflect内置方法作用在ArkTS1.2对象

  • ArkTS1.1语法
// file1.ets
export class X {
  a: string = 'hello'
  getName() { return this.a }
}

// file2.ets
import {X} from './file1'
function foo(prx: ESObject) {
 Reflect.ownKeys(prx)  // ['a']
 Reflect.set(prx, 'newField', 7)  // true
}
foo(new X())
  • ArkTS1.2语法
// solution for static ownKeys:
// file0.ets ArkTS1.2
'use static'
export getOwnKeys(prx: Any): string[] | undefined {
  if (prx instanceof Object) {
    return Reflect.ownKeys(prx)
  }
  return undefined
}

// file1.ets ArkTS1.1
import {getOwnKeys} from './file0'
export function myOwnKeys(prx: Object) {
  let ret = getOwnKeys(prx)
  if (ret == undefined) {  // prx is dynamic
    return Reflect.ownKeys(prx)
  }
  return ret
}

export function foo(prx: ESObject) {
 Reflect.ownKeys(prx)  // []
 myOwnKeys(prx)  // ['a']
 Reflect.set(prx, 'newField', 7)  // false
}

// file2.ets  ArkTS1.2
'use static'
import {foo} from './file1'
export class X {
  a: string = 'hello'
  getName() { return this.a }
}
foo(new X())
  • 编译报错信息: nan
  • 运行时报错信息: runtime cast error
  • 适配建议: 根据这些变化重新适配代码,或者避免使用这些内置底层接口
  • 变更理由: ArkTS1.2对象在动态上下文中没有own property,表现为sealed,不能修改对象布局。

ArkTS1.2动态import ArkTS1.1

  • ArkTS1.1语法
// file1.ets
export class A {}

// file2.ets
let mod = await import("./file1");
let A: ESObject = mod.A;
let a = new A() as A;

// 动态import class function enum 变量
  • ArkTS1.2语法
// file1.ets  ArkTS1.1
export class A {}

// file2.ets   ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let A: ESValue = mod.getProperty("A");
let a = A.instantiate() as A;
  • 编译报错信息: SyntaxError: Unexpected token, expected an identifier.
  • 运行时报错信息: 不涉及
  • 适配建议: 使用ESValue接口动态导入模块和调用接口
  • 变更理由: ArkTS1.2没有动态import语法,使用ESValue接口动态导入动态模块。

ArkTS1.2创建ArkTS1.1的没有无参构造函数的类的对象字面量

  • ArkTS1.1语法
// file1.ets
export class X {
  name: string;
  constructor(arg: string) {
    this.name = arg;
  }
}
// file2.ets
import { X } from "./file1";
let x: X = { name: "hello" };
  • ArkTS1.2语法
// file1.ets  ArkTS1.1
export class X {
  name: string;
  constructor(arg: string) {
    this.name = arg;
  }
}
// file2.ets  ArkTS1.2
'use static'
import { X } from "./file1";
let x: X = { name: "hello" }; // 编译报错
  • 编译报错信息 type X has no parameterless constructor
  • 运行时报错信息 不涉及
  • 适配建议 使用new: let x: X = new X('hello')
  • 变更理由 ArkTS1.2的语法限制

ArkTS1.2创建ArkTS1.1具有二义性的对象字面量

  • ArkTS1.1语法
// file1.ets
export class X {
  name: string = "";
}
export interface Y {
  name: string;
  age?: number;
}

// file2.ets
import { X, Y } from "./file1";
let x: X | Y = { name: "hello" };
  • ArkTS1.2语法
// file1.ets  ArkTS1.1
export class X {
  name: string = "";
}
export interface Y {
  name: string;
  age?: number;
}

// file2.ets  ArkTS1.2
'use static'
import { X, Y } from "./file1";
let x: X | Y = { name: "hello" }; // 编译报错
  • 编译报错信息 object literal is ambiguous for the type X | Y
  • 运行时报错信息 不涉及
  • 适配建议 使用 as确定类型 let x: X | Y = {name: 'hello'} as X
  • 变更理由 ArkTS1.2的语法限制

ArkTS1.2创建ArkTS1.1的类的对象字面量

  • ArkTS1.1语法
// file1.ets
export class A {
  name: string = "";
}

// file2.ets
import { A } from "./file1";
let a: A = { name: "hello" }; // let a = {}, a.name = 'hello'

a instanceof A; // false
  • ArkTS1.2语法
// file1.ets ArkTS1.1
export class A {
  name: string = "";
}

// file2.ets ArkTS1.2
'use static'
import { A } from "./file1";
let a: A = { name: "hello" }; // let a = new A(), a.name = 'hello'

a instanceof A; // true
  • 编译报错信息 不涉及
  • 运行时报错信息 不涉及
  • 适配建议 不要使用instanceof 判断字面量类型
  • 变更理由 ArkTS1.2的语义变更

ArkTS1.2中使用TS

ArkTS1.2访问TS独有类型的实体

实体类型如下所示:

  • any
  • unknown
  • symbol
  • Function
  • object literal (比如{x: number, y: string})
  • mixing enum (比如enum X {a = 0, b = '1'})
  • call signature (比如{(arg: number): string})
  • constructor signature (比如{new(): Object}
  • index signature (比如{[index: number]: string})
  • intersection (比如TypeA & TypeB)
  • keyof (比如interface X { props: keyof T})
  • typeof(比如let p = {x: 1, y: ''}, let q: typeof p)
  • indexed access type( 比如 MyArray = [{ name: 'Alice', age: 15 }] type Person = typeof MyArray[number])
  • conditional types (比如 type Swap<T extends A | B> = T extends A ? B : A)
  • mapped types (比如 type A = {[K in keyof T]: T[K]})
  • template literal types (比如type AB = 'A' | 'B', type AllLocaleIDs = ${AB}_id)
  • 工具类型如下所示:
    • Pick<Type, Keys>
    • Omit<Type, Keys>
    • Exclude<UnionType, ExcludedMembers>
    • Extract<Type, Union>
    • NonNullable
    • Parameters
    • ConstructorParameters
    • ReturnType
    • InstanceType
    • NoInfer
    • ThisParameterType
    • OmitThisParameter
    • ThisType
    • Uppercase
    • Lowercase
    • Capitalize
    • Uncapitalize
  • TS语法
// file1.ts
export let obj: SomeType; // SomeType是某个TS独有类型

// file2.ets
import { obj } from "./file1";
let val = obj.prop;
obj.prop = 1;
obj.foo();
obj();
let item = obj[0];
  • ArkTS1.2语法
// file1.ts
export let obj: SomeType;
// 从ArkTS1.2看来,这个声明为
// export let obj: Any

// file2.ets ArkTS1.2
'use static'
import { obj } from "./file1";
let esVal = ESValue.wrap(obj);
let val = esVal.getProperty('prop');  // let val = obj.prop
esVal.setProperty("prop", ESValue.wrap(1));  // obj.prop = 1
esVal.invokeMethod('foo');  // obj.foo()
esVal.invoke();  // obj()
let item = esVal.getProperty(0);  // let item = obj[0]
  • 编译报错信息:
    • obj does not have property prop
    • obj does not have property prop
    • obj does not have method foo
    • obj is not callable
    • obj is not indexable
  • 运行时报错信息: 不涉及。
  • 适配建议: 使用ESValue接口进行交互。
  • 变更理由: ArkTS1.2中不支持这些类型。

ArkTS1.2 for-of遍历自定义TS可迭代对象

  • TS语法
// file1.ts
export class MyIter<T> {
  [Symbol.iterator](): IterableIterator<T> {...}
}

// file2.ets
import {MyIter} from './file1'
let m = new MyIter<number>()
for (let a of m) { doSomething(a as number) }
  • ArkTS1.2语法
// file1.ts
export class MyIter<T> {
  [Symbol.iterator](): IterableIterator<T> {...}
}

// file2.ets  ArkTS1.2
'use static'
import {MyIter} from './file1'
let m = new MyIter<number>();
let eo = ESValue.wrap(m)
for (let a of eo) {
  doSomething(a.toNumber())
}
  • 编译报错信息: m is not iterable
  • 运行时报错信息: nan
  • 适配建议: 转换为ESValue再进行用for-of遍历
  • 变更理由: ArkTS1.2和TS的可迭代的定义不同。ArkTS1.2中没有Symbol.iterator方法,无法识别自定义的ts可迭代对象

Object内置方法作用在ArkTS1.2对象

  • TS语法
// file1.ts
export function foo(prx: any) {
  Object.getOwnPropertyNames(prx); // ['a']
  Object.hasOwn(prx, "a"); // true
  Object.keys(prx); // ['a']
  Object.values(prx); // [1]
}

// file2.ets
import { foo } from "./file1";
class X {
  a = 1;
}
foo(new X());
  • ArkTS1.2语法
// file1.ts
export function foo(prx: any) {
 Object.getOwnPropertyNames(prx) // []
 Object.hasOwn(prx, 'a')  // false
 Object.keys(prx)  // []
 Object.values(prx)  // []
}

// file2.ets
'use static'
import {foo} from './file1'
class X { a = 1 }
foo(ESValue.wrap(new X()))
  • 编译报错信息: parameter type does not match
  • 运行时报错信息: object is sealed
  • 适配建议: 根据这些变化重新适配代码,或者避免使用这些内置底层接口
  • 变更理由: ArkTS1.2对象在动态上下文中没有own property,表现为sealed,不能修改对象布局。

Reflect内置方法作用在ArkTS1.2对象

  • TS语法
// file1.ts
export function foo(prx: any) {
  Reflect.ownKeys(prx); // ['a']
  Reflect.set(prx, "newField", 7); // true
}

// file2.ets
import { foo } from "./file1";
class X {
  a: string = "hello";
  getName() {
    return this.a;
  }
}
foo(new X());
  • ArkTS1.2语法
// file1.ts
export function foo(prx: any) {
  Reflect.ownKeys(prx); // []
  Reflect.set(prx, "newField", 7); // false
}

// file2.ets
'use static'
import { foo } from "./file1";
class X {
  a: string = "hello";
  getName() {
    return this.a;
  }
}
foo(ESValue.wrap(new X()));
  • 编译报错信息: parameter type does not match
  • 运行时报错信息: runtime cast error
  • 适配建议: 根据这些变化重新适配代码,或者避免使用这些内置底层接口
  • 变更理由: ArkTS1.2对象在动态上下文中没有own property,表现为sealed,不能修改对象布局。

ArkTS1.2处理ts非常规异常

  • TS语法
// file1.ts
export function foo() {
  throw 123;
}

// file2.ets
import { foo } from "./file1";

try {
  foo();
} catch (e) {
  console.log("result is " + (e as number)); // 123
}
  • ArkTS1.2语法
// file1.ts
export function foo() {
  throw 123;
}

// file2.ets  // ArkTS1.2
'use static'
import { foo } from "./file1";

try {
  foo();
} catch (e) {
  let err: ESValue = (e as ESError).getValue();
  err.toNumber(); // 123
}
  • 编译报错信息: ArkTS1.2 only catch a Error instance
  • 运行时报错信息: 不涉及
  • 适配建议: ArkTS1.2只能catch Error实例,针对非常规的ts异常对象,交互是会被包装到ESError中,通过getValue()方法可以获取包装了原始异常对象的ESValue实例
  • 变更理由: ArkTS1.2中throw和catch的对象只能是Error的实例

ArkTS1.2判断TS boxed type类型

  • TS语法
// file1.ts
export let a = new Number(123);
export let b = new Boolean(true);
export let c = new String("hello");
typeof a; // 'object'
typeof b; // 'object'
typeof c; // 'object'

//file2.ets
import { a, b, c, d, e } from "./fiel1";
typeof a; // 'object'
typeof b; // 'object'
typeof c; // 'object'
  • ArkTS1.2语法
// file1.ts
export let a = new Number(123);
export let b = new Boolean(true);
export let c = new String("hello");
typeof a; // 'object'
typeof b; // 'object'
typeof c; // 'object'

//file2.ets  ArkTS1.2
'use static'
import { a, b, c, d, e } from "./fiel1";
typeof a; // 'number'
typeof b; // 'boolean'
typeof c; // 'string'
  • 编译报错信息: 不涉及
  • 运行时报错信息: 不涉及
  • 适配建议: 避免使用boxed类型,或者避免对boxed类型进行typeof
  • 变更理由: ArkTS1.2不区分基本类型和boxed类型,因此js的boxed对象在interop时会被unboxed成基本类型的值

ArkTS1.2动态import TS

  • TS语法
// file1.ts
export class A {}

// file2.ets
let mod = await import("./file1");
let A: ESObject = mod.A;
let a = new A() as A;
  • ArkTS1.2语法
// file1.ets ts
export class A {}

// file2.ets   ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let A: ESValue = mod.getProperty("A");
let a = A.instantiate() as A;
  • 编译报错信息: SyntaxError: Unexpected token, expected an identifier.
  • 运行时报错信息: 不涉及
  • 适配建议: 使用ESValue接口动态导入模块和调用接口
  • 变更理由: ArkTS1.2没有动态import语法,使用ESValue接口动态导入动态模块。

ArkTS1.2创建TS的类的对象字面量

  • TS语法
// file1.ts
export class A {
  name: string = "";
}

// file2.ets
import { A } from "./file1";
let a: A = { name: "hello" };

a instanceof A; // false
  • ArkTS1.2语法
// file1.ts
export class A {
  name: string = "";
}

// file2.ets ArkTS1.2
'use static'
import { A } from "./file1";
let a: A = { name: "hello" };

a instanceof A; // true
  • 编译报错信息: 不涉及
  • 运行时报错信息: 不涉及
  • 适配建议: 不要使用instanceof 判断字面量类型
  • 变更理由: ArkTS1.2的语义变更

ArkTS1.2中使用JS

ArkTS1.2导出js实体

  • JS语法
// file1.js
export function foo() {}
export class A {}

// file2.ets
import { foo } from "./file1";
export { foo };

export { A } from "./file1";
  • ArkTS1.2语法
// file1.js
export function foo() {}
export class A {}

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let foo = mod.getProperty("foo");
let A = mod.getProperty("A");

export { foo, A };
  • 编译报错信息: ArkTS1.2 cannot export entities from js
  • 运行时报错信息: 不涉及
  • 适配建议: 直接从js文件导入使用
  • 变更理由: ArkTS1.2中只能和有类型声明的文件进行交互。 ArkTS1.2中限制ESValue的动态行为,形成动静态更清晰的界限,减少开发者滥用ESValue导致性能劣化的场景

ArkTS1.2调用js函数和传参

  • JS语法
// file1.js
export function foo() {}
export function bar(a) {}

// file2.ets
import { foo, bar } from "./file1";
foo();
bar(123);
  • ArkTS1.2语法
// file1.js
export function foo() {}
export function bar(a) {}

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let foo = mod.getProperty("foo");
let bar = mod.getProperty("bar");
foo.invoke();
bar.invoke(ESValue.wrap(123));
  • 编译报错信息:
    • ArkTS1.2 cannot import js files directly
    • foo is not callable
  • 运行时报错信息: 不涉及
  • 适配建议: 调用ESValue的接口,接口接收参数为ESValue类型,传参时需要用wrap接口构造ESValue实例再传参。
  • 变更理由:
    • ArkTS1.2中只能和有类型声明的文件进行交互。
    • ArkTS1.2中限制ESValue的动态行为,形成动静态更清晰的界限,减少开发者滥用ESValue导致性能劣化的场景。

ArkTS1.2实例化js对象

  • JS语法
// file1.js
class foo {
  constructor(a) {}
}
// file2.ets
import { foo } from "./file1";
new foo(123);
  • ArkTS1.2语法
// file1.js
class foo {
  constructor(a) {}
}

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let foo = mod.getProperty("foo");
foo.instantiate(ESValue.wrap(123));
  • 编译报错信息 ArkTS1.2 cannot import js files directly foo is not constructor
  • 运行时报错信息 不涉及
  • 适配建议 使用ESValue的接口实例化,接口接收参数为ESValue类型,传参时需要用wrap接口构造ESValue实例再传参
  • 变更理由 ArkTS1.2中只能和有类型声明的文件进行交互。 ArkTS1.2中限制ESValue的动态行为,形成动静态更清晰的界限,减少开发者滥用ESValue导致性能劣化的场景

ArkTS1.2访问js属性

  • JS语法
// file1.js
export let foo = { name: "123" };
// file2.ets
import { foo } from "./file1";
foo.name;
foo.name = "456";
  • ArkTS1.2语法
// file1.js
export let foo = {name: '123'}

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load('./file1')
let foo = mod.getProperty('foo')
foo.getProperty('name')
foo.setProperty('name', ESValue.wrap('456'))
  • 编译报错信息 ArkTS1.2 cannot import js files directly foo does not have property 'name'
  • 运行时报错信息 不涉及
  • 适配建议 使用ESValue的接口访问属性,接口接收参数为ESValue类型,传参时需要用wrap接口构造ESValue实例再传参
  • 变更理由 ArkTS1.2中只能和有类型声明的文件进行交互。 ArkTS1.2中限制ESValue的动态行为,形成动静态更清晰的界限,减少开发者滥用ESValue导致性能劣化的场景

ArkTS1.2调用js方法和传参

  • JS语法
// file1.js
class Foo {
  bar(a) {}
}
export let foo = new Foo();
// file2.ets
import { foo } from "./file1";
foo.bar(123);
  • ArkTS1.2语法
// file1.js
class Foo {
  bar(a) {}
}

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let foo = mod.getProperty("foo");
foo.invokeMethod("bar", ESValue.wrap(123));
  • 编译报错信息 ArkTS1.2 cannot import js files directly foo does not have method 'bar'
  • 运行时报错信息 不涉及
  • 适配建议 使用ESValue的接口调用方法,接口接收参数为ESValue类型,传参时需要用wrap接口构造ESValue实例再传参
  • 变更理由 ArkTS1.2中只能和有类型声明的文件进行交互。 ArkTS1.2中限制ESValue的动态行为,形成动静态更清晰的界限,减少开发者滥用ESValue导致性能劣化的场景

ArkTS1.2访问js索引

  • JS语法
// file1.js
export let foo = { arr: [1, 2, 3] };
// file2.ets
import { foo } from "./file1";
let arr = foo.arr;
arr[1];
arr[3] = 4;
  • ArkTS1.2语法
// file1.js
export let foo = [1, 2, 3];

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let foo = mod.getProperty("foo");
let arr = foo.getProperty("arr");
arr.getProperty(1);
arr.setProperty(3, ESValue.wrap(4));
  • 编译报错信息 ArkTS1.2 cannot import js files directly foo is not indexable
  • 运行时报错信息 不涉及
  • 适配建议 使用ESValue的接口访问索引,接口接收参数为ESValue类型,传参时需要用wrap接口构造ESValue实例再传参
  • 变更理由 ArkTS1.2中只能和有类型声明的文件进行交互。 ArkTS1.2中限制ESValue的动态行为,形成动静态更清晰的界限,减少开发者滥用ESValue导致性能劣化的场景

ArkTS1.2转换js对象类型

  • JS语法
// file1.js
export let foo1 = { num: 123 };
export let foo2 = { bool: true };
export let foo3 = { str: "123" };
export let foo4 = { big: 123n };

// file2.ets
import { foo } from "./file1";
let a: number = foo1.num as number;
let a: boolean = foo2.bool as boolean;
let a: string = foo3.str as string;
let a: bigint = foo4.big as bigint;
  • ArkTS1.2语法
// file1.js
export let foo1 = { num: 123 };
export let foo2 = { bool: true };
export let foo3 = { str: "123" };
export let foo4 = { big: 123n };

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let foo1 = mod.getProperty("foo1");
let num = foo.getProperty("num");
let a1: number = num.toNumber();

let foo2 = mod.getProperty("foo2");
let bool = foo.getProperty("bool");
let a2: boolean = bool.toBoolean();

let foo3 = mod.getProperty("foo3");
let str = foo3.getProperty("str");
let a3: string = str.toString();

let foo4 = mod.getProperty("foo4");
let big = foo.getProperty("big");
let a4: bigint = big.toBigInt();
  • 编译报错信息 ArkTS1.2 cannot import js files directly cannot cast ESValue to number cannot cast ESValue to boolean cannot cast ESValue to string cannot cast ESValue to bigint
  • 运行时报错信息 不涉及
  • 适配建议 使用ESValue的接口转换类型
  • 变更理由 ArkTS1.2中只能和有类型声明的文件进行交互。 ArkTS1.2中限制ESValue的动态行为,形成动静态更清晰的界限,减少开发者滥用ESValue导致性能劣化的场景

ArkTS1.2获取js对象类型

  • JS语法
// file1.js
export let foo = { num: 123 };

// file2.ets
import { foo } from "./file1";
typeof foo.num; // 'number'
  • ArkTS1.2语法
// file1.js
export let foo = 123;

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let foo = mod.getProperty("foo");
let num = foo.getProperty("num");

num.typeOf(); // 'number'
  • 编译报错信息 ArkTS1.2 cannot import js files directly
  • 运行时报错信息 不涉及
  • 适配建议 使用ESValue的接口获取类型
  • 变更理由 ArkTS1.2中只能和有类型声明的文件进行交互。 ArkTS1.2中限制ESValue的动态行为,形成动静态更清晰的界限,减少开发者滥用ESValue导致性能劣化的场景

ArkTS1.2判断js对象类型

  • JS语法
// file1.js
export class Foo {}
export let foo = new Foo();

// file2.ets
import { Foo, foo } from "./file1";
foo instanceof Foo;
  • ArkTS1.2语法
// file1.js
export class Foo {}
export let foo = new Foo();

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let Foo = mod.getProperty("Foo");
let foo = mod.getProperty("foo");

foo.isInstanceOf(Foo);
  • 编译报错信息 ArkTS1.2 cannot import js files directly Foo is not a type
  • 运行时报错信息 不涉及
  • 适配建议 使用ESValue的接口判断类型
  • 变更理由 ArkTS1.2中只能和有类型声明的文件进行交互。 ArkTS1.2中限制ESValue的动态行为,形成动静态更清晰的界限,减少开发者滥用ESValue导致性能劣化的场景

ArkTS1.2对js对象自增自减

  • JS语法
// file1.js
export let foo = { num: 0 };

// file2.ets
import { foo } from "./file1";
let a: number = 0;
a = foo.num++;
a = ++foo.num;
a = foo.num--;
a = --foo.num;
  • ArkTS1.2语法
// file1.js
export let foo = { num: 0 };

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let foo = mod.getProperty("foo");
let a: number = 0;

// a = foo.num++
let num = foo.getProperty("num");
let tmp: number = num.toNumber();
a = tmp;
foo.setProperty("num", ESValue(tmp + 1));

// a = ++foo.num
num = foo.getProperty("num");
tmp = num.toNumber() + 1;
foo.setProperty("num", ESValue(tmp));
a = tmp;
  • 编译报错信息 ArkTS1.2 cannot import js files directly foo does not have property 'num' foo.num is not number
  • 运行时报错信息 不涉及
  • 适配建议 使用ESValue的接口转换为数字后再操作
  • 变更理由 ArkTS1.2中只能和有类型声明的文件进行交互。 ArkTS1.2中限制ESValue的动态行为,形成动静态更清晰的界限,减少开发者滥用ESValue导致性能劣化的场景

ArkTS1.2对js对象进行一元运算

  • JS语法
// file1.js
export let foo = { num: 0 };
// file2.ets
import { foo } from "./file1";
+foo.num - foo.num;
!foo.num;
~foo.num;
  • ArkTS1.2语法
// file1.js
export let foo = { num: 0 };

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let foo = mod.getProperty("foo");
let num =
  foo.getProperty("num") +
  // +foo.num
  num.toNumber() -
  // -foo.num
  num.toNumber();
// !foo.num
!num.toNumber();
// ~foo.num
~num.toNumber();
  • 编译报错信息 ArkTS1.2 cannot import js files directly foo does not have property 'num' foo.num is not number
  • 运行时报错信息 不涉及
  • 适配建议 使用ESValue的接口转换为数字后再操作
  • 变更理由 ArkTS1.2中只能和有类型声明的文件进行交互。 ArkTS1.2中限制ESValue的动态行为,形成动静态更清晰的界限,减少开发者滥用ESValue导致性能劣化的场景

ArkTS1.2对js对象进行二元运算

  • JS语法
// file1.js
export let foo = { a: 1, b: 2 };

// file2.ets
import { foo } from "./file1";
let a = foo.a;
let b = foo.b;
a + b;
a - b;
a * b;
a / b;
a % b;
a ** b;
  • ArkTS1.2语法
// file1.js
export let foo = { a: 1, b: 2 };

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let foo = mod.getProperty("foo");
let a = foo.getProperty("a").toNumber();
let b = foo.getProperty("b").toNumber();
a + b;
a - b;
a * b;
a / b;
a % b;
a ** b;
  • 编译报错信息 ArkTS1.2 cannot import js files directly foo does not have property 'a' foo does not have property 'b' a is not number b is not number
  • 运行时报错信息 不涉及
  • 适配建议 使用ESValue的接口转换为数字后再操作
  • 变更理由 ArkTS1.2中只能和有类型声明的文件进行交互。 ArkTS1.2中限制ESValue的动态行为,形成动静态更清晰的界限,减少开发者滥用ESValue导致性能劣化的场景

ArkTS1.2 await js Promise对象

  • JS语法
// file1.js
async function foo(){}
export p = foo()

// file2.ets
import {p} from './file1'
async function bar() {
  await p
}
  • ArkTS1.2语法
// file1.js
async function foo(){}
export p = foo()

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load('./file1')
let p = mod.getProperty('p')

async function bar() {
  await p.toPromise()
}
  • 编译报错信息 ArkTS1.2 cannot import js files directly p is not Promise
  • 运行时报错信息 不涉及
  • 适配建议 使用ESValue的接口转换为Promise对象后再await
  • 变更理由 ArkTS1.2中只能和有类型声明的文件进行交互。 ArkTS1.2中限制ESValue的动态行为,形成动静态更清晰的界限,减少开发者滥用ESValue导致性能劣化的场景

ArkTS1.2对js数据进行比较

  • JS语法
// file1.js
export let foo = { a: 1, b: 2 };

// file2.ets
import { foo } from "./file1";
let a = foo.a;
let b = foo.b;
a > b;
a < b;
a >= b;
a <= b;
  • ArkTS1.2语法
// file1.js
export let a = 1;
export let b = 2;

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let foo = mod.getProperty("foo");
let a = foo.getProperty("a").toNumber();
let b = foo.getProperty("b").toNumber();

a > b;
a < b;
a >= b;
a <= b;
  • 编译报错信息 ArkTS1.2 cannot import js files directly a is not number b is not number
  • 运行时报错信息 不涉及
  • 适配建议 使用ESValue的接口转换为数字后再操作
  • 变更理由 ArkTS1.2中只能和有类型声明的文件进行交互。 ArkTS1.2中限制ESValue的动态行为,形成动静态更清晰的界限,减少开发者滥用ESValue导致性能劣化的场景

ArkTS1.2对js数据进行相等判断

  • JS语法
// file1.js
class A {}
export let a = new A();
export let b = new A();

// file2.ets
import { a, b } from "./file1";
a == b;
a != b;
a === b;
a !== b;
  • ArkTS1.2语法
// file1.js
class A {}
export let a = new A();
export let b = new A();

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let a = mod.getProperty("a");
let b = mod.getProperty("b");

a.areEqual(b);
!a.areEqual(b);
a.areStrictlyEqual(b);
!a.areStrictlyEqual(b);
  • 编译报错信息 ArkTS1.2 cannot import js files directly a is not number b is not number
  • 运行时报错信息 不涉及
  • 适配建议 使用ESValue的接口判断
  • 变更理由 ArkTS1.2中只能和有类型声明的文件进行交互。 ArkTS1.2中限制ESValue的动态行为,形成动静态更清晰的界限,减少开发者滥用ESValue导致性能劣化的场景

ArkTS1.2对js对象进行条件判断

  • JS语法
// file1.js
export let foo = { isGood: true };

// file2.ets
import { foo } from "./file1";

if (foo.isGood) {
}
  • ArkTS1.2语法
// file1.js
export let foo = { isGood: true };

// file2.ets
'use static'
let mod = ESValue.load("./file1");
let foo = mod.getProperty("foo");

let isGood = foo.getProperty("isGood").toBoolean();
if (isGood) {
}
  • 编译报错信息 ArkTS1.2 cannot import js files directly foo does not have property 'isGood'
  • 运行时报错信息 nan
  • 适配建议 使用ESValue的接口转换为boolean
  • 变更理由 ArkTS1.2中只能和有类型声明的文件进行交互。 ArkTS1.2中限制ESValue的动态行为,形成动静态更清晰的界限,减少开发者滥用ESValue导致性能劣化的场景

ArkTS1.2继承js的类

  • JS语法
// file1.js
export class A {}

// file2.ets
import { A } from "./file1";
class B extends A {}
let b = new B();
  • ArkTS1.2语法
// file1.js
export class A {}

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let A = mod.getProperty("A");

let B: ESValue = ESValue.defineClass("B", () => {}, undefined, undefined, A);
let b = B.instantiate();
  • 编译报错信息 ArkTS1.2 cannot import js files directly A is not a class
  • 运行时报错信息 nan
  • 适配建议 使用ESValue的接口构造JS类并传递js父类
  • 变更理由 ArkTS1.2中只能和有类型声明的文件进行交互。 ArkTS1.2中限制ESValue的动态行为,形成动静态更清晰的界限,减少开发者滥用ESValue导致性能劣化的场景

ArkTS1.2处理js非常规异常

  • JS语法
// file1.js
export function foo() {
  throw 123;
}

// file2.ets
import { foo } from "./file1";

try {
  foo();
} catch (e) {
  console.log("result is " + (e as number)); //123
}
  • ArkTS1.2语法
// file1.js
export function foo() {
  throw 123;
}

// file2.ets
'use static'
let mod = ESValue.load("./file1");
let foo = mod.getProperty("foo");

try {
  foo.invoke();
} catch (e) {
  let err: ESValue = (e as ESError).getValue();
  err.toNumber(); // 123
}
  • 编译报错信息 ArkTS1.2 cannot import js files directly ArkTS1.2 only catch a Error instance
  • 运行时报错信息 不涉及
  • 适配建议 ArkTS1.2只能catch Error实例,针对非常规的js异常对象,交互是会被包装到ESError中,通过getValue()方法可以获取包装了原始异常对象的ESValue实例
  • 变更理由 ArkTS1.2中throw和catch的对象只能是Error的实例

ArkTS1.2访问js的boxed对象

  • JS语法
// file1.js
export let foo = {
  num: new Number(123),
  bool: new Boolean(true),
  str: new String("hello"),
};

// file2.ets
import { foo } from "./file1";
typeof foo.num; // 'object'
typeof foo.bool; // 'object'
typeof foo.str; // 'object'
  • ArkTS1.2语法
// file1.js
export let foo = {
  num: new Number(123),
  bool: new Boolean(true),
  str: new String("hello"),
};

// file2.ets
'use static'
let mod = ESValue.load("./file1");
let foo = mod.getProperty("foo");

foo.getProperty("num").typeOf(); // 'number'
foo.getProperty("bool").typeOf(); // 'boolean'
foo.getProperty("str").typeOf(); // 'string'
  • 编译报错信息 ArkTS1.2 cannot import js files directly foo does not have properties 'num', 'bool', 'str'
  • 运行时报错信息 不涉及
  • 适配建议 避免使用boxed类型,或者避免对boxed类型进行typeof
  • 变更理由 ArkTS1.2不区分基本类型和boxed类型,因此js的boxed对象在interop时会被unboxed成基本类型的值

ArkTS1.2遍历js对象

  • JS语法
// file1.js
export let foo = { arr: [1, 2, 3] };
// file2.ets
import { foo } from "./file1";
let arr = foo.arr;
let len = arr.length as number;
for (let i = 0; i < len; ++i) {
  arr[i] as number;
  arr[i] = 0;
}
  • ArkTS1.2语法
// file1.js
export let foo = { arr: [1, 2, 3] };

// file2.ets  ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let foo = mod.getProperty("foo");
let arr = foo.getProerptyByName("arr");
let len = arr.getProerptyByName("length").toNumber();
for (let i = 0; i < len; ++i) {
  arr.getPropertyByIndex(i).toNumber();
  arr.setPropertyByIndex(i, ESValue.wrap(0));
}
  • 编译报错信息 ArkTS1.2 cannot import js files directly foo does not have property 'arr' arr does not have property 'length' arr is not indexable
  • 运行时报错信息 不涉及
  • 适配建议 使用ESValue接口访问索引和属性
  • 变更理由 ArkTS1.2中只能和有类型声明的文件进行交互。 ArkTS1.2中限制ESValue的动态行为,形成动静态更清晰的界限,减少开发者滥用ESValue导致性能劣化的场景

js调用ArkTS1.2函数和传参

  • JS语法
// file1.js
export function handle(cb) {
  let p = { name: "hello" };
  cb(p);
}

// file2.ets
import { handle } from "./file1";
interface Person {
  name: string;
}

function foo(p: Person) {}
let lambda = (p: Person) => {};

handle(foo);
handle(lambda);
  • ArkTS1.2语法
// file1.js
export function handle(cb) {
  let p = { name: "hello" };
  cb(p);
}

// file2.ets
'use static'
let mod = ESValue.load("./file1");
let handle = mod.getProperty("handle");
interface Person {
  name: string;
}
function foo(p: Person) {}
// solution: function foo(p: Any) {}
let lambda = (p: Person) => {};
// solution: let lambda = (p: Any) => {}

handle.invoke(ESValue.wrap(foo));
handle.invoke(ESValue.wrap(lambda));
  • 编译报错信息 ArkTS1.2 cannot import js files directly foo is not callable
  • 运行时报错信息 runtime cast error
  • 适配建议 确保传参匹配参数声明的类型
  • 变更理由 ArkTS1.2的函数运行时会检查参数类型,需要确保参数类型匹配

js增删改ArkTS1.2对象属性

  • JS语法
// file1.js
export function foo(obj) {
  obj.newField = 1; // 增加属性
  delete obj.data; // 删除属性
  obj.name = "123"; // 修改属性值(同类型)
  obj.name = { firstName: "456" }; // 修改属性值(不同类型)
}

// file2.ets
import { foo } from "./file1";
class X {
  name: string = "";
  data: number = 0;
}
foo(new X());
  • ArkTS1.2语法
// file1.js
export function foo(obj) {
  obj.newField = 1; // 增加属性   运行时报错
  delete obj.data; // 删除属性   运行时报错
  obj.name = "123"; // 修改属性值(同类型)OK
  obj.name = { firstName: "456" }; // 修改属性值(不同类型)运行时报错
}

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let foo = mod.getProperty("foo");
class X {
  name: string = "";
  data: number = 0;
}
foo.invoke(ESValue.wrap(new X()));
  • 编译报错信息 ArkTS1.2 cannot import js files directly foo is not callable
  • 运行时报错信息 object is sealed
  • 适配建议 避免动态修改对象布局。需要新增的属性提前在类型中声明,需要删除的属性使用undefined置空。
  • 变更理由 ArkTS1.2的对象布局在编译时就确定了,不能动态修改

js Object内置方法作用在ArkTS1.2对象

  • JS语法
// file1.js
export function foo(prx) {
  Object.getOwnPropertyNames(prx); // ['a']
  Object.hasOwn(prx, "a"); // true
  Object.keys(prx); // ['a']
  Object.values(prx); // [1]
}

// file2.ets
import { foo } from "./file1";
class X {
  a = 1;
}
foo(new X());
  • ArkTS1.2语法
// file1.js
export function foo(prx) {
 Object.getOwnPropertyNames(prx) // []
 Object.hasOwn(prx, 'a')  // false
 Object.keys(prx)  // []
 Object.values(prx)  // []
}

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load('./file1')
let foo = mod.getProperty('foo')
class X { a = 1 }
foo.invoke(ESValue.wrap(new X()))
  • 编译报错信息 ArkTS1.2 cannot import js files directly foo is not callable
  • 运行时报错信息 object is sealed
  • 适配建议 根据这些变化重新适配代码,或者避免使用这些内置底层接口
  • 变更理由 ArkTS1.2对象在动态上下文中没有own property,表现为sealed,不能修改对象布局。

jsReflect内置方法作用在ArkTS1.2对象

  • JS语法
// file1.js
export function foo(prx) {
  Reflect.ownKeys(prx); // ['a']
  Reflect.set(prx, "newField", 7); // true
}

// file2.ets
import { foo } from "./file1";
class X {
  a: string = "hello";
  getName() {
    return this.a;
  }
}
foo(new X());
  • ArkTS1.2语法
// file1.js
export function foo(prx) {
  Reflect.ownKeys(prx); // []
  Reflect.set(prx, "newField", 7); // false
}

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let foo = mod.getProperty("foo");
class X {
  a: string = "hello";
  getName() {
    return this.a;
  }
}
foo.invoke(ESValue.wrap(new X()));
  • 编译报错信息 ArkTS1.2 cannot import js files directly foo is not callable
  • 运行时报错信息 runtime cast error
  • 适配建议 根据这些变化重新适配代码,或者避免使用这些内置底层接口
  • 变更理由 ArkTS1.2对象在动态上下文中没有own property,表现为sealed,不能修改对象布局。

js对ArkTS1.2对象进行展开语法

  • JS语法
// file1.js
export function foo(obj) {
  let x = {...obj} // x will be { a = 1; b = 2; c = 3 }
  let {a, b, ...rest} = obj  // a will be 1, b will be 2, rest will be {c: 3}

// file2.ets
import {foo} from './file1'
class X { a = 1; b = 2; c = 3 }
foo(new X())

// class interface Record
  • ArkTS1.2语法
// file1.js
export function foo(obj) {
  let x = {...obj} // x will be empty object {}. because there is no own properties for static object
  // solution: let x = {a: obj.a, b: obj.b, c: obj.c}
  // keys + Reflect.get
  let {a, b, ...rest} = obj
  // a will be 1, b will be 2, rest will be empty object {}, because there is no own properties for static object
  // solution: let rest = {c: obj.c}

// file2.ets  // ArkTS1.2
'use static'
let mod = ESValue.load('./file1')
let foo = mod.getProperty('foo')
class X { a = 1; b = 2; c = 3 }
foo.invoke(ESValue.wrap(new X()))
  • 编译报错信息 ArkTS1.2 cannot import js files directly foo is not callable
  • 运行时报错信息 不涉及
  • 适配建议 根据这些变化重新适配代码,或者避免使用解构语法。
  • 变更理由 ArkTS1.2对象在动态上下文中没有own property,相关解构操作会失效。

ArkTS1.2动态import JS

  • JS语法
ArkTS1.2动态导入JS
  • ArkTS1.2语法
不涉及;
  • 编译报错信息 SyntaxError: Unexpected token, expected an identifier.
  • 运行时报错信息 SyntaxError: Unexpected token, expected an identifier.
  • 适配建议
// file1.js
export class A {}

// file2.ets   ArkTS1.2
'use static'
let mod = ESValue.load("./file1");
let A: ESValue = mod.getProperty("A");
let a = A.instantiate();
  • 变更理由 使用ESValue接口动态导入模块和调用接口

ArkTS1.2并发场景下的交互

并发执行ArkTS1.1&ArkTS1.2混合代码的主要方式通过ArkTS1.2的上下文;ArkTS1.1中需要执行ArkTS1.1&ArkTS1.2混合代码的场景需要迁移到ArkTS1.2来保证易用性和性能。

ArkTS1.2使用ArkTS1.1的场景

ArkTS1.2与ArkTS1.1的Promise互操作

// file1.ets ArkTS1.1
export let p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("foo");
  }, 300);
});
// file2.ets ArkTS1.2
'use static'
import { p } from "file1";
// OK
p.then((s: String) => {
  console.log(s);
});
// OK
p.catch((e: Object) => {
  console.error(e);
});
// OK
p.finally(() => {
  console.log("Completed");
});
// OK
async function foo() {
  const result = await p;
}

ArkTS1.2与ArkTS1.1的async function互操作

// file1.ets ArkTS1.1
export async function foo() {}
// file2.ets ArkTS1.2
'use static'
import { foo } from "file1";
// OK, call foo
function baz() {
  foo();
}
// OK, await foo
await foo();
async function bar() {
  await foo();
}
// OK, use the return value as a 1.2 Promise
const p = foo();

ArkTS1.2单线程异步上下文与ArkTS1.1对象互操作

  • 使用当前线程的动态上下文,规格同主线程规格
// file1.ets ArkTS1.1
export let s = new String("123");
export function foo(arg: Object) {
  console.log(typeof arg);
  return 42;
}
// file2.ets ArkTS1.2
'use static'
import { s, foo } from "file1";
function bar() {
  let p = new Promise<number>(
    (resolve: (v: number) => void, _: (error: Object) => void) => {
      // OK
      foo.invoke(s);
      resolve(42);
    }
  );
}
async function baz() {
  // OK
  foo.invoke(s);
}

ArkTS1.2多线程异步上下文与ArkTS1.1对象互操作

  • 跨线程通信时,适用1.1线程间通信的规格,但sendData / onReceiveData不再支持,用1.2线程间通信代替
  • 使用当前线程的动态上下文,规格同主线程规格
// file1.ets ArkTS1.1
export let s = new String('123')
@concurrent
export function foo(arg: Object){
   console.log(typeof arg)
   return 42;
}
export function bar() {
  return foo(42); // 违反闭包原则,报错
}
// file2.ets ArkTS1.2
'use static'
import { s, foo, bar } from 'file1'
// 1.2 Taskpool
function baz() {
  // OK. print 'object'
  taskpool.execute(foo, s);
  // NO. not allowed to call 1.1 non-concurrenct function
  taskpool.execute(bar);
}
// 1.2 EAWorker
let eaw : EAWorker = new EAWorker();
// OK. print 'object'
let p = eaw.run(foo, s);
// NO. not allowed to call 1.1 non-concurrenct function
let q = eaw.run(bar)
cont result = p.Await();
eaw.stop();

协程不支持互操作

// file1.ets ArkTS1.1
export let function foo() {}
export async function bar() {}
export let p = new Promise<number>((resolve, reject) => {
  setTimeout(() => {
    resolve(42);
  }, 1000);
});
// file2.ets ArkTS1.2
'use static'
import {foo, bar, A, p} from 'file1'
async function baz() {
  foo(); // NO
  await bar(); // NO
  await p; // NO
}
launch(baz)  // NO

ArkTS1.1使用ArkTS1.2的场景

ArkTS1.1与ArkTS1.2的Promise互操作

// file1.ets ArkTS1.2
'use static'
export let p = new Promise<String>(
  (resolve: (v: number) => void, _: (error: Object) => void) => {
    setTimeout(() => {
      resolve("foo");
    }, 300);
  }
);
// file2.ets ArkTS1.1
import { p } from "file1";
// OK
p.then((value) => {
  console.log(value);
});
// OK
p.catch((error) => {
  console.error(error);
});
// OK
p.finally(() => {
  console.log("Completed");
});
// OK
await p;

ArkTS1.1与ArkTS1.2的async function互操作

// file1.ets ArkTS1.2
'use static'
export async function foo() {}
// file2.ets ArkTS1.1
import { foo } from "file1";
// OK, call foo
function baz() {
  foo();
}
// OK, await foo
await foo();
async function bar() {
  await foo();
}
// OK, use the return value as a 1.1 Promise
const p = foo();

ArkTS1.1单线程异步上下文与ArkTS1.2对象互操作

  • 主线程使用主线程规格,非主线程(Taskpool和Worker)不支持互操作
// file1.ets ArkTS1.2
'use static'
export class A {}
export function foo(arg: Object) {
  arg as A;
}
// file2.ets ArkTS1.1
import { foo, A } from "file1";
const p = new Promise((resolve, reject) => {
  foo(123); // RTE
  foo(new A()); // OK
  resolve("foo");
});
async function bar() {
  foo(123); // RTE
  foo(new A()); // OK
}

ArkTS1.1多线程异步上下文不支持互操作

  • Taskpool和Worker上下文不支持互操作
// file1.ets ArkTS1.2
'use static'
export class A {}
export function foo(arg: Object) {
  arg as A;
}
// file2.ets ArkTS1.1
import { foo, A } from "file1";
foo(new A()); // OK
// file3.ets ArkTS1.1
import { foo, A } from "file1";
function bar() {
  // NO
  taskpool.execute(foo, new A());
}
// NO
let workerInstance = new worker.ThreadWorker("file2.ets");