ArkTS1.2迁移语法规范

ArkTS1.2在引入了静态类型系统、增强的并发能力的同时,也引入了与ArkTS1.1在语法和语义上的一部分差异。本文罗列了所有在ArkTS1.2中被限制的ArkTS1.1特性,并提供了重构代码的建议。

限定关键字

规则: arkts-invalid-identifier

级别: error

ArkTS1.2中对关键字和保留字做了严格定义。代码中不能使用这些关键字作为变量名称。

ArkTS1.1

let as: number = 1;
const abstract: string = "abstract";

ArkTS1.2

let a = 1;
const abstract1: string = "abstract";

数值类型语义变化

规则: arkts-numeric-semantic

级别: error

在ArkTS1.2中,为了获得更好的执行效率,整型数字字面量默认是int类型。

ArkTS1.1

let n = 1;
console.log(n / 2)  // output: 0.5

let arr = [1, 2, 3];

function multiply(x = 2, y = 3) { // 需要明确类型
  return x * y;
}

function divide(x: number, y: number) {
  return x / y;
} // 函数返回值

let num = Math.floor(4.8); // num 可能是 int
let value = parseInt("42"); // value 可能是 int

function identity<T>(value: T): T {
  return value;
}
identity(42); // 42 可能推导为 int

ArkTS1.2

let n: number = 1;
console.log(n / 2)  // output: 0.5

let m = 1;
console.log(m / 2)  // output: 0

let arr: number[] = [1, 2, 3];

function multiply(x: number = 2, y: number = 3): number {
  return x * y;
}

function divide(x: number, y: number): number {
  return x / y;
}

let num: number = Math.floor(4.8);
let value: number = parseInt("42");

function identity<T>(value: T): T {
  return value;
}
identity(42 as number);

void类型只能用在返回类型的场景

规则: arkts-limited-void-type

级别: error

在ArkTS1.2中,void仅作为类型使用。void类型没有实体。

ArkTS1.1

let s: void = foo();
let t: void | number = foo();

function process<T>(input: T): T {
  return input;
}
let result = process<void>(foo()); 

type VoidAlias = void; 

let { x }: { x: void } = { x: foo() };

function execute(callback: void) {
  callback();
}

let x = fun() as void;

ArkTS1.2

function foo(): void {}
foo();

function bar(): void {}

function execute(callback: () => void) {
  callback();
}
fun();

不支持void操作符

规则: arkts-no-void-operator

级别: error

在ArkTS1.2中,undefined作为关键字不能作为变量名称,因此不需要通过void操作符获取undefined。

ArkTS1.1

let s = void 'hello';
console.log(s);  // output: undefined

let a = 5;
let b = void (a + 1);

function logValue(value: any) {
    console.log(value);
}
logValue(void 'data');

let fn = () => void 0;

ArkTS1.2

(() => {
    'hello'
    return undefined;
})()

let a = 5;
let b = (() => {
    a + 1;
    return undefined;
})();  // 替换为 IIFE

logValue((() => {
    'data';
    return undefined;
})());  // 替换为 IIFE

let fn = () => undefined;  // 直接返回 `undefined`

限定使用字面量类型

规则: arkts-limited-literal-types

级别: error

ArkTS1.2不支持数字字面量类型,布尔字面量类型。

ArkTS1.2提供了更多细化的数值类型供开发者选择,更关注数值的范围而非某个特定的数字值,同时,为了更好的代码简洁性和避免引入歧义,不引入复杂的数值字面量类型语法。

ArkTS1.1

let n1: 1 = 1;
let n2: 0.1 = 0.1;
let f: true = true;

function getOne(): 1 {
  return 1; 
}
function isAvailable(): true {
  return true;
}

function setFlag(flag: true) {
  console.log(flag);
}
function setPrecision(precision: 0.1) {
  console.log(precision);
}

interface Config {
  readonly enable: true;
  readonly threshold: 100;
}

ArkTS1.2

let n1: int = 1;
let n2: number = 0.1;
let f: boolean = true;

function getOne(): int {
  return 1;
}
function isAvailable(): boolean {
  return true;
}

function setFlag(flag: boolean) {
  console.log(flag);
}
function setPrecision(precision: number) {
  console.log(precision);
}

interface Config {
  readonly enable: boolean;
  readonly threshold: int;
}

不支持arguments对象

规则: arkts-no-arguments-obj

级别: error

ArkTS1.2对函数调用进行严格的参数检查,参数个数不符时编译报错,因此不需要在函数体内通过arguments机制获取参数。

ArkTS1.1

function foo(u: string) {
  console.log(arguments[0]);
}

function bar(a: number, b?: number) {
  if (arguments.length === 1) {
    console.log("Only one argument passed");
  }
}

function sum() {
  let total = 0;
  for (let i = 0; i < arguments.length; i++) {
    total += arguments[i];
  }
  return total;
}

function test() {
  console.log(arguments.callee);
}

ArkTS1.2

function foo(u: string) {
  console.log(u);
}

function bar(a: number, b?: number) {
  if (b === undefined) {
    console.log("Only one argument passed");
  }
}

function sum(...args: number[]) {  
  // 使用 `...rest` 替代 `arguments`
  return args.reduce((acc, num) => acc + num, 0);
}

function test() {
  console.log(test);  // 直接使用函数名
}

数组索引必须是整型数据

规则:arkts-array-index-expr-type

级别:error

ArkTS1.2支持数值类型的细化,为了实现数组更快的访问,数组索引表达式必须是整数类型。

ArkTS1.1

function foo (index: number) {
  let array = [1, 2, 3] 
  let element = array[index]
}

function getIndex(): number {
  return Math.random() * 10; // 可能返回小数
}

let array = [1, 2, 3];
for (let i: number = 0; i < array.length; i++) { // 违反规则
  console.log(array[i]);
}

ArkTS1.2

function foo (index: int) {
  let array = [1, 2, 3] 
  let element = array[index]
}

function getIndex(): int {
  return Math.floor(Math.random() * 10);  // 转换为 `int`
}

let array = [1, 2, 3];
for (let i: int = 0; i < array.length; i++) { // 改为 `int`
  console.log(array[i]);
}

不支持通过负数访问数组

规则:arkts-array-index-negative

级别:error

ArkTS1.2不支持使用负整数访问数组元素。

ArkTS1.1

let an_array = [1, 2, 3];
let element = an_array [-1];
console.log(getElement(an_array, -1)); // 违反规则
for (let i: int = -1; i < an_array.length; i++) { // 违反规则
  console.log(an_array[i]);
}

function getElement(arr: number[], index: int) {
  return arr[index]; // 可能接收负数索引
}

ArkTS1.2

let an_array = [1, 2, 3];
let element = an_array [1];
console.log(getElement(an_array, 1)); // 传递非负索引
for (let i: int = 0; i < an_array.length; i++) { // 仅允许非负索引
  console.log(an_array[i]);
}

function getElement(arr: number[], index: int) {
  if (index < 0) throw new Error("Index must be a non-negative integer");
  return arr[index]; // 仅允许非负整数
}

增加数组越界运行时检查

规则:arkts-runtime-array-check

级别:error

为了保证类型安全,在访问数组元素时,ArkTS1.2会对索引的合法性进行校验。

ArkTS1.1

let a: number[] = []
a[100] = 5; // 可能越界

ArkTS1.2

let a: number[] = []
if (100 < a.length) {
  a[100] = 5  // a[100]的值为5
}

arkts-no-tuples-arrays

规则:arkts-no-tuples-arrays

级别:error

ArkTS1.2中数组和元组是不同的类型,运行时使用元组类型可以获得更好的性能。

ArkTS1.1

const tuple: [number, number, boolean] = [1, 3.14, true];
const array: (number|boolean) [] = tuple;

const tuple: Array<number | boolean> = [1, 3.14, true];  // 违反规则

function getTuple(): (number | boolean)[] {  // 违反规则
  return [1, 3.14, true];
}
getTuple([1, 3.14, true]);  // 传入元组

type Point = (number | boolean)[];  // 违反规则
const p: Point = [3, 5, true];

ArkTS1.2

const tuple: [number, number, boolean] = [1, 3.14, true];
const array:  [number, number, boolean] = tuple;

const tuple: [number, number, boolean] = [1, 3.14, true];  // 正确使用元组

function getTuple(): [number, number, boolean] {  // 正确使用元组
  return [1, 3.14, true];
}
getTuple([1, 3.14, true]);

type Point = [number, number, boolean];  // 使用元组
const p: Point = [3, 5, true];

函数类型

规则:arkts-incompatible-function-types

级别:error

TypeScript允许对函数类型的变量进行更宽松的赋值,而在ArkTS1.2中,将对函数类型的赋值进行更严格的检查。函数类型转换时,参数遵循逆变(Contravariance)规则,返回类型遵循协变(Covariance)规则。

ArkTS1.1

type FuncType = (p: string) => void;
let f1: FuncType =
    (p: string): number => {
        return 0
    }
let f2: FuncType = (p: any): void => {};

class Animal {}
class Dog extends Animal {}
type FuncType = () => Animal;
let f: FuncType = (): Dog => new Dog(); // 在 TypeScript 允许,但在 ArkTS 可能不允许

type FuncType2 = (dog: Dog) => void;
let f: FuncType2 = (animal: Animal) => {}; // 违反规则

ArkTS1.2

type FuncType = (p: string) => void
let f1: FuncType =
  	(p: string) => {
        ((p: string): number => {
            return 0
        })(p) 
    }
let f2: FuncType = (p: string): void => {};

class Animal {}
class Dog extends Animal {}
type FuncType = () => Animal;
let f: FuncType = (): Animal => new Animal();// 返回 `Animal`

type FuncType2 = (dog: Dog) => void;
let f: FuncType = (dog: Dog) => {}; // 参数类型严格匹配

不支持指数操作符

规则:arkts-no-exponent-op

级别:error

ArkTS1.2不支持指数运算符(****=),采用语言基础库。

ArkTS1.1

let x = 2 ** 5;

let y = 3;
y **= 4; // 违反规则

let result = (1 + 2) ** (3 * 2); // 违反规则

function power(base: number, exponent: number) {
  return base ** exponent; // 违反规则
}

let values = [1, 2, 3];
let squared = values.map(v => v ** 2); // 违反规则

ArkTS1.2

let x = Math.pow(2, 5);

let y = 3;
y = Math.pow(y, 4); // 直接使用 `Math.pow()`

let result = Math.pow(1 + 2, 3 * 2); // 直接使用 `Math.pow()`

function power(base: number, exponent: number) {
  return Math.pow(base, exponent); // 使用 `Math.pow()`
}

let values = [1, 2, 3];
let squared = values.map(v => Math.pow(v, 2)); // 使用 `Math.pow()`

不支持正则表达式

规则:arkts-no-regexp-literals

级别:error

ArkTS1.2不支持正则表达式字面量。

ArkTS1.1

let regex: RegExp = /bc*d/;
let regex = /\d{2,4}-\w+/g; // 违反规则
function matchPattern(str: string) {
  return str.match(/hello\s+world/i); // 违反规则
}

let text = "Hello world!";
let result = text.replace(/world/, "ArkTS"); // 违反规则

let items = "apple,banana, cherry".split(/\s*,\s*/); // 违反规则

ArkTS1.2

let regex: RegExp =  new RegExp('bc*d');
let regex = new RegExp('\\d{2,4}-\\w+', 'g'); // 使用 `RegExp` 类
function matchPattern(str: string) {
  let regex = new RegExp('hello\\s+world', 'i'); // 使用 `RegExp`
  return str.match(regex);
}

let text = "Hello world!";
let regex = new RegExp('world'); // 使用 `RegExp` 类
let result = text.replace(regex, "ArkTS");

let regex = new RegExp('\\s*,\\s*'); // 使用 `RegExp`
let items = "apple,banana, cherry".split(regex);

enum中不支持成员为不同类型数据

规则:arkts-no-enum-mixed-types

级别:error

enum用来表示一组离散的数据,使用浮点数据不符合enum的设计理念。使用浮点数据可能造成精度损失的问题。因此,ArkTS1.2中enum的值必须为整型数据。

ArkTS1.1

enum Size {
  UP = 1.5,
  MIDDLE = 1,
  DOWN = 0.75
}

ArkTS1.2

enum Size{ 
  UP = 1,
  MIDDLE = 2,
  DOWN = 3
}

不支持为函数增加属性

规则:arkts-no-func-props

级别:error

ArkTS1.2上不支持在函数上动态添加属性。

ArkTS1.1

function foo(path: string): void {
  console.log(path)
}
foo.baz = 1

const obj = {
  foo(path: string): void {
    console.log(path);
  }
};
obj.foo.baz = 2; // 违反规则

function createLogger() {
  function log(message: string) {
    console.log(message);
  }
  log.level = "debug"; // 违反规则
  return log;
}

const logger = createLogger();
console.log(logger.level);

function counter() {
  counter.count = (counter.count || 0) + 1; // 违反规则
  return counter.count;
}
console.log(counter());

ArkTS1.2

class T {
  static foo(path: string): void {
    console.log(path)
  }
  static bar: number = 1
}

class T {
  static foo(path: string): void {
    console.log(path);
  }

  static baz: number = 2;
}
T.foo("example");
console.log(T.baz);

class Logger {
  static level = "debug";

  static log(message: string) {
    console.log(message);
  }
}
Logger.log("test");
console.log(Logger.level);

class Counter {
  static count = 0;

  static increment() {
    this.count += 1;
    return this.count;
  }
}
console.log(Counter.increment());

不支持TS装饰器

规则:arkts-no-ts-decorators

级别:error

ArkTS1.2中不支持将类作为对象,不能通过装饰器中对类做动态改变。

ArkTS1.1

function decorateKlass(target: Object) {
  console.log("decorateKlass")
}

@decorateKlass // 违反规则
class Person {
    age: number = 12
}

ArkTS1.2

class Person {
    age: number = 12
}

class PersonHelper {
  static createPerson(): Person {
     console.log("decorateKlass")
     return new Person()
  }
}

类实现接口时,不能用类方法替代对应interface属性

规则:arkts-no-method-overriding-field

级别:error

ArkTS1.2不支持structural type,属性和方法不能互相转换。

ArkTS1.1

interface Person {
  cb: () => void
}

class student implements Person{
  cb() {}
} 

interface Transformer<T> {
  transform: (value: T) => T; // 违反规则
}

class StringTransformer implements Transformer<string> {
  transform(value: string) { return value.toUpperCase(); }  // 违反规则
}

ArkTS1.2

interface Person {
  cb(): void
}

class student implements Person{
  cb() {}
}

interface Transformer<T> {
  transform(value: T): T;  // 变成方法
}

class StringTransformer implements Transformer<string> {
  transform(value: string) { return value.toUpperCase(); }  // 正确
}

限定switch语句中case语句类型

规则:arkts-switch-expr

级别:error

ArkTS1.2的switch表达式类型只能为number,string,enum。

ArkTS1.1

const isTrue = true;
switch (isTrue) {
    case true: // 违反规则
        console.log('It\'s true'); break;
    case false:  // 违反规则
        console.log('It\'s false'); break;
}

const obj = { value: 1 };
switch (obj) {  // 违反规则
    case { value: 1 }:
        console.log('Matched'); break;
}

const arr = [1, 2, 3];
switch (arr) {  // 违反规则
    case [1, 2, 3]: 
        console.log('Matched'); break;
}

ArkTS1.2

const isTrue = 'true';
switch (isTrue) {
    case 'true': 
        console.log('It\'s true'); break;
    case 'false': 
        console.log('It\'s false'); break;
}

const objValue = 1;  // 仅存储值
switch (objValue) {
    case 1:
        console.log('Matched'); break;
}

const arrValue = '1,2,3';  // 变成字符串
switch (arrValue) {
    case '1,2,3':
        console.log('Matched'); break;
}

不支持重复case语句

规则:arkts-case-expr

级别:error

ArkTS1.2不支持Switch语句的中case重复,便于提高代码可读性。

ArkTS1.1

const num = 1;
switch (num) {
    case 1:
        console.log('First match');
    case 1:
        console.log('Second match');
        break;
    default:
        console.log('No match');
}

enum Status {
    Active,
    Inactive
}

const state = Status.Active;
switch (state) {
    case Status.Active:
        console.log('User is active');
        break;
    case Status.Active: // 违反规则
        console.log('Already active');
        break;
}

ArkTS1.2

const num = 1;
switch (num) {
    case 1:
        console.log('First match');
        console.log('Second match');
        break;
    default:
        console.log('No match');
}

switch (state) {
    case Status.Active:
        console.log('User is active');
        console.log('Already active'); // 代码合并
        break;
}

不支持lazy关键字

规则:arkts-no-lazy-import

级别:error

ArkTS1.2支持默认懒加载,无需lazy关键字。

ArkTS1.1

import lazy { m } from 'module'
import lazy { a, b } from 'module1'; // 违反规则
import { c } from 'module2';

ArkTS1.2

import { m } from 'module'
import { a, b } from 'module1'; // 移除 lazy
import { c } from 'module2';

不支持动态import

规则:arkts-no-dynamic-import

级别:error

ArkTS1.2中模块加载默认支持懒加载。

ArkTS1.1

function main(): void {
  import('./file').then((m) => {
    console.log(m.Data.name)
  })
}

document.getElementById("btn")?.addEventListener("click", async () => {
  const module = await import('./utils');  // 错误: 在ArkTS中动态`import()`是不支持的.
  module.doSomething();
});

function getModule() {
  return import('./heavyModule')  // 错误: 在ArkTS中动态`import()`是不支持的.
    .then((m) => m.default);
}

ArkTS1.2

import { Data } from './file'
import { doSomething } from './utils';  // 静态import是可以的.
import heavyModule from './heavyModule';  // 静态import是可以的.

function main(): void {
  console.log(Data.name)
}

document.getElementById("btn")?.addEventListener("click", () => {
  doSomething();
});

function getModule() {
  return heavyModule;
}

不支持副作用导入

规则:arkts-no-side-effect-import

级别:error

ArkTS1.2中模块加载默认支持懒加载,无法实现导入副作用的功能。

ArkTS1.1

// logger.ets
console.log("Logger initialized!");

// main.ets
import "./logger";
console.log("Main program running...");

ArkTS1.2

// main.ets
console.log("Logger initialized!");
console.log("Main program running...");

不支持globalThis

规则:arkts-no-globalthis

级别:error

由于ArkTS1.2不支持动态更改对象的布局,因此不支持全局作用域和globalThis。

ArkTS1.1

// 全局文件中
var abc = 100;

// 从上面引用'abc'
let x = globalThis.abc;

ArkTS1.2

// file1
export let abc: number = 100;

// file2
import * as M from 'file1'

let x = M.abc;

不支持Funcion.bind方法

规则:arkts-no-func-bind

级别:error

ArkTS不允许使用标准库函数Function.bind。标准库使用这些函数来显式设置被调用函数的this参数。

ArkTS1.1

class MyClass {
  constructor(public name: string) {}

  greet() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

const instance = new MyClass("Alice");
const boundGreet = instance.greet.bind(instance); // 违反规则,不允许使用 Function.bind
boundGreet();

ArkTS1.2

class MyClass {
  constructor(public name: string) {}

  greet() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

const instance = new MyClass("Alice");
const boundGreet = () => instance.greet(); // 使用箭头函数
boundGreet(); // Hello, my name is Alice

不支持将类作为对象

规则:arkts-no-classes-as-obj

级别:error

在ArkTS中,class声明的是一个新的类型,不是一个值。因此,不支持将class用作对象(例如将class赋值给一个变量)。

ArkTS1.1

class MyClass {
  constructor(public name: string) {}
}

let obj = MyClass; // 违反规则

ArkTS1.2

class MyClass {
  constructor(name: string) {}
}

// 需要通过反射来实现
let className = "path.to.MyClass";
let linker = Class.ofCaller()!.getLinker();
let classType: ClassType | undefined = linker.getType(className) as ClassType;

arkts-limited-stdlib

规则:arkts-limited-stdlib

级别:error

由于TypeScript或JavaScript标准库中的大部分接口与动态特性有关,所以在ArkTS中禁止使用以下接口:

Object: getPrototypeOf

不支持structural typing

规则:arkts-no-structural-typing

级别:error

ArkTS1.2不支持structural typing,编译器无法比较两种类型的publicAPI并决定它们是否相同。使用其他机制,例如继承、接口或类型别名。

ArkTS1.1

// case1
class A {
  v: number = 0
}

class B {
  v: number = 0
}

let a = new B() as A

// case2
class C<T> {
  u: T
}

let b: C<B> = new C<A>()

// case3
class A {
  u: number = 0
}

class B {
  u: number = 0
}

(): A => { return new B() }

class A {
  v: number = 0
}

class B {
  v: number = 0
}
class C<T> {
  u: T;
}

let b: C<B> = new C<A>(); // 违反规则

ArkTS1.2

// case1
class A {
  v: number = 0
}

class B {
  v: number = 0
}

let a = new B()

// case2
class C<T> {
  u: T
}

let b: C<A> = new C<A>()

// case3
class A {
  u: number = 0
}

class B {
  u: number = 0
}

(): B => { return new B() }

class A {
  v: number = 0
}

class B {
  v: number = 0
}
let b: C<A> = new C<A>(); // 使用相同的泛型类型

禁止extends/implements表达式

规则:arkts-no-extends-expression

级别:error

ArkTS1.2中规范了类的继承,类不能作为对象来继承一个表达式。

ArkTS1.1

class A {
  v: number = 0
}

let a = A;

class B extends a { // 违反规则
  u: number = 0
}

function getBase() {
  return class {
    w: number = 0;
  };
}

class B extends getBase() { // 违反规则
  u: number = 0;
}

interface I {
  w: number;
}

let i = I;

class B implements i { // 违反规则
  w: number = 0;
}

class A {
  v: number = 0;
}

class B extends new A() { // 违反规则
  u: number = 0;
}

ArkTS1.2

class A {
  v: number = 0
}

class B extends A { // 直接继承类
  u: number = 0
}

class Base {
  w: number = 0;
}

class B extends Base { // 直接继承类
  u: number = 0;
}

interface I {
  w: number;
}

class B implements I { // 直接使用接口
  w: number = 0;
}

class A {
  v: number = 0;
}

class B extends A { // 直接继承类
  u: number = 0;
}

不支持类TS重载

规则:arkts-no-ts-overload

级别:error

ArkTS1.2不支持TS-like的重载,使用不同的函数体可以提高执行效率。

ArkTS1.1

function foo(): void
function foo(x: string): void
function foo(x?: string): void { // 违反规则
  /*body*/
}

function sum(x: number, y: number): number;
function sum(x: number, y: number, z: number): number;
function sum(x: number, y: number, z?: number): number {  // 违反规则
  return z ? x + y + z : x + y;
}

function foo(): string;
function foo(x: number): number;
function foo(x?: number): string | number {  // 违反规则
  return x !== undefined ? x * 2 : "default";
}

ArkTS1.2

function foo(x?: string): void {
  /*body*/
}

function sumTwo(x: number, y: number): number {  // 独立实现
  return x + y;
}

function sumThree(x: number, y: number, z: number): number {  // 独立实现
  return x + y + z;
}

function fooString(): string {  // 独立实现
  return "default";
}

function fooNumber(x: number): number {  // 独立实现
  return x * 2;
}

enum的key不能是字符串

规则:arkts-identifiers-as-prop-names

级别:error

ArkTS1.2不支持将字符串作为class、interface、enum等属性或元素的名称,需要使用标识符来表示。

ArkTS1.1

enum A{
 'red' = '1'
}

ArkTS1.2

enum A{
  red = '1'
}

创建泛型实例需要类型实参

规则:arkts-no-inferred-generic-params

级别:error

ArkTS1.2中,创建泛型实例时需要类型实参。

ArkTS1.1

new Array() // 违反规则

new Map(); // 违反规则

class Box<T> {
  value: T;
  constructor(value: T) {
    this.value = value;
  }
}

let box = new Box(42); // 违反规则

ArkTS1.2

new Array<SomeType>() // 指定类型

new Map<string, number>(); // 显式指定键值类型

let box = new Box<number>(42); // 明确指定类型

不支持[]访问对象属性

规则:arkts-no-props-by-index

级别:error

在ArkTS1.2中,对象结构在编译时已确定。为避免运行时出现错误和更好地提升性能,在ArkTS1.2中不能使用[]的方式动态访问object类型对象的属性。

ArkTS1.1

function foo(u: object) {
  u['key'] // 违反规则
}

const person = { name: "Alice", age: 30 };
console.log(person['name']); // 违反规则

const data = JSON.parse('{ "name": "Alice" }');
console.log(data['name']); // 违反规则

ArkTS1.2

function foo(m: Map<string, Object>) {
  m.get('key') // 使用 `Map`
}

console.log(person.name); // 直接使用 `.` 访问

interface UserData {
  name: string;
}
const data: UserData = JSON.parse('{ "name": "Alice" }');
console.log(data.name); // 直接使用点访问符

对象字面量只包含属性不包含方法

规则:arkts-obj-literal-props

级别:error

ArkTS1.2中不支持在对象字面量中定义方法。因为静态语言中类的方法被所有实例所共享,无法通过对象字面量重新定义方法。

ArkTS1.1

class A {
  foo: () => void = () => {}
}

let a: A = {
  foo() { // 违反规则
    console.log('hello')
  }
}

interface Person {
  sayHello: () => void;
}

let p: Person = {
  sayHello() {  // 违反规则,方法定义方式错误
    console.log('Hi');
  }
};

type Handler = {
  foo(): void; 
};

let handler: Handler = {
  foo() {  // 违反规则
    console.log("Executing handler");
  }
};

ArkTS1.2

class A {
  foo : () => void = () => {}
}

let a: A = {
  foo: () => {
    console.log('hello')
  }
}

let p: Person = {
  sayHello: () => {  // 使用属性赋值方式
    console.log('Hi');
  }
};

type Handler = {
  foo: () => void;  
};

let handler: Handler = {
  foo: () => {  // 修正方法定义方式
    console.log("Executing handler");
  }
};

对象字面量生成类的实例

规则:arkts-obj-literal-generate-class-instance

级别:error

ArkTS1.2中对象字面量会生成类的实例。

ArkTS1.1

class A {
  v: number = 0
}

let a: A = { v: 123 }
console.log(a instanceof A)  // false

class A {
  v: number = 0;
  hello() {
    return "Hello";
  }
}

let a: A = { v: 123 };
console.log(a.hello()); // 报错,a 没有 hello() 方法

class A {
  v: number = 0;
}

let a: A = { v: 123 };
console.log(Object.getPrototypeOf(a) === A.prototype); // false

ArkTS1.2

class A {
  v: number = 0
}

let a: A = { v: 123 }
console.log(a instanceof A)  //  true

class A {
  v: number = 0;
  hello() {
    return "Hello";
  }
}

let a: A = { v: 123 };
console.log(a.hello()); // 正常执行 "Hello"

class A {
  v: number = 0;
}

let a: A = { v: 123 };
console.log(Object.getPrototypeOf(a) === A.prototype); // true

增强对联合类型属性访问的编译时检查

规则:arkts-common-union-member-access

级别:error

在ArkTS1.2中,对象的结构在编译时就确定了。为了避免访问联合类型后出现运行时错误,ArkTS1.2在编译时会对联合类型的同名属性进行编译检查,要求同名属性具有相同的类型。

ArkTS1.1

class A {
  v: number = 1
}

class B {
  u: string = ''
}

function foo(a: A | B) {
  console.log(a.v) // 违反规则
  console.log(a.u) // 违反规则
}

ArkTS1.2

class A {
  v: number = 1
}

class B {
  u: string = ''
}

function foo(a: A) {
  console.log(a.v)
}

function foo(a: B) {
  console.log(a.u)
}

类的静态属性需要有初始值

规则:arkts-class-static-initialization

级别:error

ArkTS1.2遵循null-safety,需要为属性赋上初始值。

ArkTS1.1

class B {}

class A {
  static b: B
}

class A {
  static count: number; // 违反规则,必须初始化
}

class A {
  static config: { theme: string }; // 违反规则,必须初始化
}

class A {
  static name: string;

  constructor() {
    A.name = "default"; // 违反规则,静态属性必须在定义时初始化
  }
}

ArkTS1.2

class B {}

class A {
  static b? : B
  static b: B | undefined = undefined
}

class A {
  static count: number = 0; // 提供初始值
}

class A {
  static config: { theme: string } = { theme: "light" }; // 提供初始值
}

class A {
  static name: string = "default"; // 在定义时初始化
}

不支持TS-like Function类型的调用方式

规则:arkts-no-ts-like-function-call

级别:error

ArkTS1.2会对函数类型进行更严格的编译器检查。函数返回类型需要严格定义来保证类型安全,因此不支持TS-likeFunction类型。

ArkTS1.1

let f: Function = () => {} // 违反规则

function run(fn: Function) {  // 违反规则
  fn();
}

let fn: Function = (x: number) => x + 1; // 违反规则

class A {
  func: Function = () => {}; // 违反规则
}

function getFunction(): Function { // 违反规则
  return () => {};
}

ArkTS1.2

type F<R> = () => R;
type F1<P, R> = (p:  P) => R

let f: F<void> = () => {}

function run(fn: () => void) {  // 指定返回类型
  fn();
}

let fn: (x: number) => number = (x) => x + 1; // 明确参数类型

class A {
  func: () => void = () => {}; // 明确类型
}

function getFunction(): () => void { // 明确返回类型
  return () => {};
}

不支持可选方法

规则:arkts-optional-methods

级别:error

ArkTS1.2中类的方法被所有类的实例所共享,增加可选方法的支持会增加开发者判断空值的成本,影响性能。

ArkTS1.1

interface InterfaceA {
  aboutToDisappear?(): void
}
class ClassA {
  aboutToDisappear?(): void {}
}

ArkTS1.2

interface InterfaceA {
  aboutToDisappear?: () => void
}
class ClassA {
  aboutToDisappear?: () => void = () => {}
}

实例方法当作对象时会绑定this

规则:arkts-instance-method-bind-this

级别:error

ArkTS1.2中实例方法被当作lambda对象传递时,会捕获上下文的this,避免类型不安全的行为。

ArkTS1.1

class A {
  n: string = 'a'
  foo() { console.log (this.n) }
}
let a = new A()
const method = a.foo
method()   // 无法读取未定义的属性'n'.

ArkTS1.2

class A {
  n: string = 'a'
  foo() { console.log (this.n) }
}
let a = new A()
const method = a.foo
method()   // 输出a

namespace内方法不能重名

规则:arkts-no-duplicate-function-name

级别:error

由于ArkTS1.2中会将多个名称相同的namespace合并成一个namespace,所以namespace内方法不能重名,否则会导致冲突。

ArkTS1.1

namespace A {
  export function foo() {  // 错误:命名空间 'A' 中重复导出函数 'foo'.
    console.log('test1');
  }
}

namespace A {
  export function foo() {  // 错误:命名空间 'A' 中重复导出函数 'foo'.
    console.log('test2');
  }
}

ArkTS1.2

namespace A {
  export function foo1() {  // 重命名导出函数
    console.log('test1');
  }
}

namespace A {
  export function foo2() {
    console.log('test2');
  }
}

arkts-no-ctor-prop-decls

规则:arkts-no-ctor-prop-decls

级别:error

ArkTS1.2不支持在constructor中声明类字段。在class中声明这些字段。

ArkTS1.1

class A {
  constructor(readonly a: string) {
  }
}

class Base {
  readonly b: string = "base";
}

class A extends Base {
  constructor(override readonly b: string) {  // 违反规则
    super();
  }
}

ArkTS1.2

class A {
  readonly a: string
  constructor(a: string) {
    this.a = a
  }
}

class Base {
  readonly b: string = "base";
}

class A extends Base {
  override readonly b: string;  // 显式声明字段
  constructor(b: string) {
    super();
    this.b = b;
  }
}

不支持tagged templates

规则:arkts-no-tagged-templates

级别:error

ArkTS1.2规范函数调用方式,支持字符串相加的用法,不支持Tagged templates(标签模板字符串)。

ArkTS1.1

function myTag(strings: TemplateStringsArray, value: string): string {
    return strings[0] + value.toUpperCase() + strings[1];
}

const name = 'john';
const result = myTag`Hello, ${name}!`;
console.log(result);

function formatTag(strings: TemplateStringsArray, first: string, last: string): string {  
    return `${strings[0]}${first.toUpperCase()} ${last.toUpperCase()}${strings[1]}`;
}

const firstName = 'john';
const lastName = 'doe';
const result = formatTag`Hello, ${firstName} ${lastName}!`;  // 违反规则
console.log(result);

ArkTS1.2

function myTagWithoutTemplate(strings: string, value: string): string {
    return strings + value.toUpperCase();
}

const name = 'john';

const part1 = 'Hello, ';
const part2 = '!';
const result = myTagWithoutTemplate(part1, name) + part2;
console.log(result);

function formatWithoutTemplate(greeting: string, first: string, last: string, end: string): string {  
    return greeting + first.toUpperCase() + ' ' + last.toUpperCase() + end;
}

const firstName = 'john';
const lastName = 'doe';
const result = formatWithoutTemplate('Hello, ', firstName, lastName, '!');  // 直接使用函数参数
console.log(result);

不支持确定赋值断言

规则:arkts-no-definite-assignment

级别:error

ArkTS1.2不支持确定赋值断言。改为在声明变量的同时为变量赋值。

ArkTS1.1

let x!: number // 提示:在使用前将x初始化

initialize();

function initialize() {
  x = 10;
}

console.log('x = ' + x);

ArkTS1.2

function initialize(): number {
  return 10;
}

let x: number = initialize();

console.log('x = ' + x);

Record增加运行时类型

规则:arkts-record-add-runtime-type

级别:error

ArkTS1.2中对象字面量会生成类的实例。

ArkTS1.1

let a: Record<string, number> = { 'v': 123 };  // Record是编译时类型,运行时仍是动态对象
a.v;  // 需要使用[]方式访问

ArkTS1.2

let a: Record<string, number> = { 'v': 123 };  // Record是编译时类型,运行时仍是动态对象
console.info(a instanceof Record) // true
a['v'];  

as具有运行时语义

规则:arkts-no-ts-like-as

级别:error

ArkTS1.1中的as只在编译时提供类型信息,如果类型断言失败,报错时机取决于后续的代码操作。

ArkTS1.2中的as会在运行时进行类型检查和可能的类型转换,如果类型断言失败,会立即抛出错误。

ArkTS1.1

// ArkTS1.1
interface I {}
class A implements I {
  m: number = 0;
}

class B implements I {
  n: string = 'a';
}

let a: A = new A();
let i: I = a;
let t: B = i as B; // ArkTS1.1:正常编译运行,ArkTS1.2:运行时异常
t.n.toString();     // ArkTS1.1:运行时崩溃

ArkTS1.2

// ArkTS1.2
interface I {}
class A implements I {
  m: number = 0;
}

class B implements I {
  n: string = 'a';
}

let a: A = new A();
let i: I = a;
if (i instanceof B) {
  let t: B = i as B;  // ArkTS1.2:运行时正常
  t.n.toString();     // ArkTS1.2:运行时正常
}

catch语句中是error类型

规则:arkts-no-ts-like-catch-type

级别:error

在ArkTS1.1上catch语句中的e是any类型。因此,编译器不会对catch语句中的异常进行编译时类型检查。当ArkTS1.1上限制throw时,只能抛出Error类型。

在ArkTS1.2的静态模式中,类型必须明确,同时需考虑与ArkTS1.1的兼容性。对于catch(e)的语法,默认e为Error类型。

ArkTS1.1

try {
  throw new Error();
} catch(e) {  // e是any类型
  e.message; // ArkTS1.1编译通过,运行正常
  e.prop;     // ArkTS1.1编译通过,输出undefined
}

ArkTS1.2

try {
  throw new Error();
} catch(e:Error) {  // e是Error类型
  e.message;   // ArkTS1.2编译通过,运行正常
  e.prop;      // ArkTS1.2编译错误,需要将e转换成需要处理的异常类型,例如:(e as SomeError).prop
}

不支持逻辑赋值运算

规则:arkts-unsupport-operator

级别:error

  1. 当前暂不支持&&=, ||=, ??=逻辑赋值运算符,通过迁移工具提示开发者修改源码,不提供自动修复能力。

ArkTS1.1

let a = 1;
a &&= 2;    // 结果: 2,ArkTS1.2暂不支持
a ||= 3;   // 结果: 2,ArkTS1.2暂不支持
a ??= 4;  // 结果: 2,ArkTS1.2暂不支持

ArkTS1.2

let a = 1;
a = a && 2;   // 结果: 2
a = a || 3;   // 结果: 2
a = a ?? 4;   // 结果: 2

非十进制bigint字面量

规则:arkts-only-support-decimal-bigint-literal

级别:error

当前暂不支持非十进制bigint字面量,通过迁移工具提示开发者修改源码,不提供自动修复能力。

ArkTS1.1

let a1: bigint = 0xBAD3n;  // 十六进制字面量,ArkTS1.2暂不支持
let a2: bigint = 0o777n;   // 八进制字面量,ArkTS1.2暂不支持
let a3: bigint = 0b101n;  // 二进制字面量,ArkTS1.2暂不支持

ArkTS1.2

let a1: bigint = BigInt(0xBAD3);
let a2: bigint = BigInt(0o777);
let a3: bigint = BigInt(0b101);

数值类型和bigint类型的比较

规则:arkts-numeric-bigint-compare

级别:error

当前暂不支持数值类型和bigint类型的比较,迁移工具将提示开发者修改源码,不提供自动修复能力。

ArkTS1.1

let n1: number = 123;
let n2: bigint = 456n;

n1 <= n2;   // 编译通过
n1 == n2;   // 编译失败
n1 >= n2;   // 编译通过

ArkTS1.2

let n1: number = 123;
let n2: bigint = 456n;

BigInt(n1) <= n2;
BigInt(n1) == n2;
BigInt(n1) >= n2;

new Number/Boolean/String不再是"object"类型

规则:arkts-primitive-type-normalization

级别:error

  1. 在ArkTS1.2中primitive type和boxed type是相同的类型,这样可以提高语言一致性和性能。 比较Number/Boolean/String时比较的是值而不是对象。

  2. 在ArkTS1.1上,boxed类型通过new创建。在获取其类型、比较boxed类型对象时会产生意外行为,这是因为对象比较时是通过引用进行比较,而不是值。通常直接使用primitive type性能更高效,内存占用更少(相比之下对象会占用更多内存)。

ArkTS1.1

typeof new Number(1) // 结果: "object"
new Number(1) == new Number(1);  //结果: false
if (new Boolean(false)) {} // 在if语句中new Boolean(false)为true

ArkTS1.2

typeof new Number(1)// 结果: "number"
new Number(1) == new Number(1);  //结果: true
if (new Boolean(false)) {}      // 在if语句中new Boolean(false)为false

enum的元素不能作为类型

规则:arkts-no-enum-prop-as-type

级别:error

ArkTS1.1上的枚举是编译时概念,在运行时仍是普通对象。ArkTS1.2遵循静态类型,需要在运行时为enum提供类型。因此,ArkTS1.2上枚举的每个元素是枚举类的实例(在运行时才确定),无法成为编译时的静态类型信息。这与ArkTS1.2整体类型设计上不支持实例类型相违背。

ArkTS1.1

enum A { E = 'A' }
function foo(a: A.E) {}

ArkTS1.2

enum A { E = 'A' }
function foo(a: 'A') {}

// ...
enum A { E = 'A' }
function foo(a: A) {}

不支持debugger

规则:arkts-no-debugger

级别:error

  1. 静态类型语言具备编译时检查和强类型约束,调试通常由IDE完成,已具备较强大的调试机制。

  2. debugger会侵入式修改源码。

  3. debugger语句会被优化,造成行为不一致。

ArkTS1.1

// ArkTS1.1 
// ...
debugger;
// ...

ArkTS1.2

// ArkTS1.2   移除debugger语句
// ...

不支持空数组/稀疏数组

规则:arkts-no-sparse-array

级别:error

  1. ArkTS1.2遵循静态类型,空数组需要能根据上下文推导出数组元素的类型,否则会有编译错误。

  2. ArkTS1.2的数组是连续存储的,空位(如 [1, , , 2])会浪费内存。‌

  3. ArkTS1.2遵循空值安全,无法使用默认undefined表示空缺。

ArkTS1.1

let a = []; // ArkTS1.2,编译错误,需要从上下文中推导数组类型
let b = [1, , , 2]; // 不支持数组中的空位
b[1];  // undefined 

ArkTS1.2

let a: number[] = [];  // 支持,ArkTS1.2上可以从上下文推导出类型
let b = [1, undefined, undefined, 2];

智能类型差异

规则:arkts-no-ts-like-smart-type

级别:error

在ArkTS1.1中,由于对象不是线程间共享的,编译器在做类型推导和分析时无需考虑并发场景。

在ArkTS1.2中,由于对象是多线程共享的,编译器在做类型推导和分析时需要考虑并发场景下变量类型/值的变化。

智能转换: 编译器会在某些场景下(如instanceof、null检查、上下文推导等)识别出对象的具体类型,自动将变量转换为相应类型,而无需手动转换。

ArkTS1.1

class AA {
  public static instance?: number;
  getInstance(): number {
    if (!AA.instance) {
      return 0;
    }
    return AA.instance;       // ArkTS1.2编译错误,返回值和返回类型不匹配
  }
}

ArkTS1.2

class AA {
  public static instance?: number;
  getInstance(): number {
    let a = AA.instance       // ArkTS1.2上,需要通过局部变量做智能转换
    if (!a) {
      return 0;
    }
    return a;
  }
}

数组/元组类型在继承关系中遵循不变性原则

规则:arkts-array-type-immutable

级别:error

ArkTS1.2上数组在继承关系中遵循不变性原则,可以通过编译时检查保证类型安全,将潜在的运行时错误提前到编译期,避免运行时失败,从而提高执行性能。

ArkTS1.1

class A {
  a: number = 0;
}

class B {
  b: number = 0;
}

// ArkTS1.1 
let arr1: A[] = [new A()];
let arr2: (A | B)[] = arr1;      // ArkTS1.2编译错误

ArkTS1.2

class A {
  a: number = 0;
}

class B {
  b: number = 0;
}

// ArkTS1.2 
let arr1: [ A | B ] = [new A()];
let arr2: [ A | B ] = arr1;       // 需要相同类型的元组

默认参数必须放在必选参数之后

规则:arkts-default-args-behind-required-args

级别:error

默认参数放在必选参数之前没有意义,ArkTS1.1上调用该接口时仍须传递每个默认参数。

ArkTS1.1

function add(left: number = 0, right: number) { 
  return left + right;
}

ArkTS1.2

function add(left: number, right: number) {
  return left + right;
}

class的懒加载

规则:arkts-class-lazy-import

级别:error

ArkTS1.2的类在使用时进行加载或初始化,以提升启动性能,减少内存占用。

ArkTS1.1

class C {
  static {
    console.info('init');  // ArkTS1.2上不会立即执行
  }
}

ArkTS1.2

// ArkTS1.2  如果依赖没有被使用的class执行逻辑,那么将该段逻辑移出class
class C {
  static {}
}
console.info('init');

方法继承/实现参数遵循逆变原则,返回类型遵循协变原则

规则:arkts-method-inherit-rule

级别:error

ArkTS1.2子类方法覆写父类方法,参数类型须遵循逆变原则,可以通过编译时检查保证类型安全,将潜在的运行时错误提前到编译期,避免运行时失败,无需运行时检查,从而提高执行性能。

逆变/协变: 用来描述类型转换后的继承关系,如果A、B表示类型,f()表示类型转换,≤表示继承关系(A≤B表示A是由B派生出来的子类),则有:

  • f()为逆变时,当A≤B时有f(B)≤f(A)成立。

  • f()为协变时,当A≤B时有f(A)≤f(B)成立。

ArkTS1.1

// ArkTS1.1  
class A {
  a: number = 0;
}
class B {
  b: number = 0;
}

class Base {
  foo(obj: A | B): void {}
}
class Derived extends Base {
  override foo(obj: A): void {      // 可以覆写父类方法,ArkTS1.2编译错误
    console.info(obj.a.toString());
  }
}

ArkTS1.2

// ArkTS1.2
class A {
  a: number = 0;
}
class B {
  b: number = 0;
}

class Base {
  foo(obj: A | B): void {}
}
class Derived extends Base {
  override foo(obj: A | B): void {
    if (obj instanceof A) {
      console.info(obj.a.toString());
    }
  }
}

Enum不可以通过索引访问成员

规则:arkts-enum-no-props-by-index

级别:error

  1. ArkTS1.1上已对索引访问元素的语法做了限制,ArkTS1.2对枚举场景增强约束。具体内容请参考不支持通过索引访问字段

  2. ArkTS1.1上枚举是动态对象,ArkTS1.2是静态类型,枚举具有运行时类型。为获得更高的性能,对[]访问做了限制。

ArkTS1.1

enum TEST {
  A,
  B,
  C
}

TEST['A'];       // ArkTS1.2上不支持这种语法
TEST[0];    // ArkTS1.2上不支持这种语法

ArkTS1.2

enum TEST {
  A,
  B,
  C
}

TEST.A;          // 使用.操作符或者enum的值
TEST.A.getName();  // 使用enum对应的方法获取enum的key

对象没有constructor

规则:arkts-obj-no-constructor

级别:error

ArkTS1.2支持天然共享的能力,运行时需要确定类型信息。实现上不再基于原型的语言,而是基于class的语言。

ArkTS1.1

class A {}
let a = new A().constructor;   // ArkTS1.2上编译错误

ArkTS1.2

class A {}
let a = new A();
let cls = Type.of(a); 

子类有参构造函数需要显式定义,且必须调用父类的构造函数

规则:arkts-subclass-must-call-super-constructor-with-args

级别:error

  1. ArkTS1.1在运行时没有对函数调用的检查,同时利用arguments机制获取所有参数(ArkTS1.2上不支持这个特性)并传入父类构造函数。ArkTS1.2对函数参数的个数和类型会进行编译时检查,确保程序的安全和正确性,因此ArkTS1.2上不支持这种写法。

  2. ArkTS1.2支持方法重载,构造函数可能有多个实现体,在ArkTS1.2上支持这个特性会造成子类继承父类时的二义性。

ArkTS1.1

class A {
  constructor(a: number) {}
}
class B extends A {}                // ArkTS1.2上编译报错
let b = new B(123);

ArkTS1.2

class A {
  constructor(a: number) {}
}
class B extends A {
  constructor(a: number) {
    super(a)
  }
}
let b = new B(123);

不支持可选元组类型

规则:arkts-no-optional-tuple

级别:error

ArkTS1.2不支持可选元组类型。通过编译时检查保证类型安全,将潜在的运行时错误提前到编译期,避免运行时失败,从而提高执行性能。

ArkTS1.1

let t: [number] = [1];
let t1: [number, boolean?] = t;   // ArkTS1.2编译错误

ArkTS1.2

let t: [number] = [1];
let t1: [number, boolean] | [number] = t;

不支持超大数字字面量

规则:arkts-no-big-numeric-literal

级别:error

  1. ArkTS1.2支持更多数值类型细化,可以获得更好的性能。超出int/long/double范围的数字字面量会有编译错误。

  2. 支持隐式转换会造成额外的性能损耗。

  3. 浮点数据的隐式转换可能带来精度的损失,违反开发者预期。清晰的数值边界可以提升代码准确性和可读性。

ArkTS1.1

let s = 1000000000000000000000000000000000000; // ArkTS1.1会转换成浮点形式数据,ArkTS1.2编译错误
let t = 1E+309;                               // ArkTS1.1会转换为Infinity,ArkTS1.2编译错误

ArkTS1.2

let s = 1000000000000000000000000000000000000.0; // ok,浮点形式数据
let t = Infinity;                                // ok,值为Infinity

class/interface的变量名称需要是合法标识符

规则:arkts-identifier-as-prop-names

级别:error

  1. ArkTS1.1上已经进行约束,ArkTS1.2对边界场景增强约束。详细内容请参考对象的属性名必须是合法的标识符

  2. 静态类型中对属性的访问是静态的,可以获得更好的执行性能。

  3. 使用字符串作为属性名称可能带来二义性。

ArkTS1.1

class A {
  's' = 1;
}

ArkTS1.2

class A {
  s = 1;
}

子类不可以声明和父类的方法同名的lamada类型的属性

规则:arkts-no-subclass-lamada-prop-name-same-as-superclass-method

级别:error

不同于ArkTS1.1上的动态对象(属性和方法一致),ArkTS1.2上的属性与方法有本质区别。属性用以保存类实例的状态,是可变的。方法定义类对象的行为或功能,被类的所有实例所共有,不能被改变。

同时,ArkTS1.1和ArkTS1.2不支持属性和实例方法同名。因此在ArkTS1.2上,类的继承关系中不能将同名属性和方法相互覆写。

ArkTS1.1

class A {
  foo() {
    console.info('A');
  }
}

class B extends A {
  foo: () => void = () => {
    console.info('B');
  }
}

ArkTS1.2

class A {
  foo() {
    console.info('A');
  }
}

class B extends A {
  foo() {
    console.info('B');
  }
}

子类不能在static context中调用super

规则:arkts-no-super-call-in-static-context

级别:error

  1. ArkTS1.2不再基于原型实现继承。没有原型/构造函数的概念,无法实现动态替换原型,因此无需通过super动态访问父类。

  2. super定义在子类的静态上下文中,容易混淆super的指向,与在实例方法中super指向父类实例相冲突,造成开发者的混用。使用类名的方式访问静态成员更清晰、可维护,易于开发者理解。

ArkTS1.1

class A {
  static foo() {
    return 123;
  }
}

class B extends A {
  static foo() {
    return super.foo() + 456;
  }
}

ArkTS1.2

class A {
  static foo() {
    return 123;
  }
}

class B extends A {
  static foo() {
    return A.foo() + 456;
  }
}

类继承含属性的接口时,需要实现属性的get/set方法

规则:arkts-class-implement-interface-prop-getter-setter

级别:error

ArkTS1.2遵循严格的类型检查,可以通过编译时检查保证类型安全,将潜在的运行时错误提前到编译期,避免运行时失败,从而提高执行性能。

ArkTS1.1

interface I {
  v: number
}

class A implements I {
  get v(): number {
    return 1;
  }
}

ArkTS1.2

interface I {
  readonly v: number
}

class A implements I {
  get v(): number {
    return 1;
  }
}

不能将超出枚举范围的值赋值给枚举类型的变量

规则:arkts-out-of-enum-index

级别:error

ArkTS1.2上枚举类型是类型安全的,编译器会进行严格检查,避免应用中的非预期行为或错误。同时,枚举的值是编译时确定的,如果在运行时赋值超出范围的值,会对开发者造成困惑,降低易用性(TS在新版本上也增强了枚举场景的编译检查)。

ArkTS1.1

enum T {
  A = 0,
  B = 1,
  C = 2
}

let num: number = 123;

let t1: T = 0;
let t2: T = -1;
let t3: T = num;

ArkTS1.2

运行时赋值枚举类型在ArkTS1.2上没有直接的替代写法。如果想超出枚举范围赋值,建议使用类/容器等其他数据结构实现。

不支持不定长的元组类型

规则:arkts-no-unfixed-len-tuple

级别:error

ArkTS1.2上不支持可变元组,可以通过编译时检查保证类型安全,将潜在的运行时错误提前到编译期,避免运行时失败,从而提高执行性能。

ArkTS1.1

const s: [string, ...boolean[]]=['', true];

ArkTS1.2

const s: (string | boolean)[] =['', true];

类实例不支持关系表达式

规则:arkts-no-class-instance-relational-expression

级别:error

  1. ArkTS1.2中遵循类型安全,为避免隐式转化行为,关系表达式的操作符必须是数值类型、字符串类型、布尔类型、枚举类型。同时,支持隐式转化可能引发非预期的异常。

  2. 对象的比较缺乏默认语义,为了语言的一致性和明确性,不支持不同对象的比较。

ArkTS1.1

class A {
  valueOf () {
    return 3;
  }
}

class B {
  valueOf () {
    return 4;
  }
}

let a = new A();
let b = new B();
console.info('a<b:', a < b);

ArkTS1.2

class A {
  valueOf () {
    return 3;
  }
}

class B {
  valueOf () {
    return 4;
  }
}

let a = new A();
let b = new B();
console.info(a.valueOf() < b.valueOf());

instanceof的目标类型不能是函数

规则:arkts-no-instanceof-func

级别:error

ArkTS1.2上不再基于原型实现继承,没有原型/构造函数的概念,不能通过任意函数创建对象。因此instanceof的目标类型不能是函数。

ArkTS1.1

function foo() {}
function bar(obj: Object) {
  console.info('obj instanceof foo :' ,obj instanceof foo);
}

ArkTS1.2

function bar(obj: Object) {
console.info('obj instanceof foo :', obj instanceof string);
}

静态加载包内模块某一文件时ohmurl路径变更

规则:arkts-ohmurl-path-change

级别:error

ArkTS1.2中在静态加载包内模块某一文件时ohmurl路径必须写全,不可省略路径中的"src/main"。

ArkTS1.1

// library/ets/components/Index.ets
import { MainPage } from 'library/ets/components/MainPage'

ArkTS1.2

// library/ets/components/Index.ets
import { MainPage } from 'library/src/main/ets/components/MainPage'