需要显式标注泛型函数类型实参
规则:arkts-no-inferred-generic-params
级别:错误
如果可以从传递给泛型函数的参数中推断出具体类型,ArkTS允许省略泛型类型实参。否则,省略泛型类型实参会发生编译时错误。
禁止仅基于泛型函数返回类型推断泛型类型参数。
TypeScript
function choose<T>(x: T, y: T): T {
return Math.random() < 0.5 ? x: y;
}
let x = choose(10, 20); // 推断choose<number>(...)
let y = choose('10', 20); // 编译时错误
function greet<T>(): T {
return 'Hello' as T;
}
let z = greet() // T的类型被推断为“unknown”
ArkTS
function choose<T>(x: T, y: T): T {
return Math.random() < 0.5 ? x: y;
}
let x = choose(10, 20); // 推断choose<number>(...)
let y = choose('10', 20); // 编译时错误
function greet<T>(): T {
return 'Hello' as T;
}
let z = greet<string>();
需要显式标注对象字面量的类型
规则:arkts-no-untyped-obj-literals
级别:错误
在ArkTS中,需要显式标注对象字面量的类型,否则,将发生编译时错误。在某些场景下,编译器可以根据上下文推断出字面量的类型。
在以下上下文中不支持使用字面量初始化类和接口:
- 初始化具有any、Object或object类型的任何对象
- 初始化带有方法的类或接口
- 初始化包含自定义含参数的构造函数的类
- 初始化带readonly字段的类
例子1
TypeScript
let o1 = {n: 42, s: 'foo'};
let o2: Object = {n: 42, s: 'foo'};
let o3: object = {n: 42, s: 'foo'};
let oo: Object[] = [{n: 1, s: '1'}, {n: 2, s: '2'}];
ArkTS
class C1 {
n: number = 0
s: string = ''
}
let o1: C1 = {n: 42, s: 'foo'};
let o2: C1 = {n: 42, s: 'foo'};
let o3: C1 = {n: 42, s: 'foo'};
let oo: C1[] = [{n: 1, s: '1'}, {n: 2, s: '2'}];
例子2
TypeScript
class C2 {
s: string
constructor(s: string) {
this.s = 's =' + s;
}
}
let o4: C2 = {s: 'foo'};
ArkTS
class C2 {
s: string
constructor(s: string) {
this.s = 's =' + s;
}
}
let o4 = new C2('foo');
例子3
TypeScript
class C3 {
readonly n: number = 0
readonly s: string = ''
}
let o5: C3 = {n: 42, s: 'foo'};
ArkTS
class C3 {
n: number = 0
s: string = ''
}
let o5: C3 = {n: 42, s: 'foo'};
例子4
TypeScript
abstract class A {}
let o6: A = {};
ArkTS
abstract class A {}
class C extends A {}
let o6: C = {}; // 或 let o6: C = new C()
例子5
TypeScript
class C4 {
n: number = 0
s: string = ''
f() {
console.log('Hello');
}
}
let o7: C4 = {n: 42, s: 'foo', f: () => {}};
ArkTS
class C4 {
n: number = 0
s: string = ''
f() {
console.log('Hello');
}
}
let o7 = new C4();
o7.n = 42;
o7.s = 'foo';
例子6
TypeScript
class Point {
x: number = 0
y: number = 0
}
function getPoint(o: Point): Point {
return o;
}
// TS支持structural typing,可以推断p的类型为Point
let p = {x: 5, y: 10};
getPoint(p);
// 可通过上下文推断出对象字面量的类型为Point
getPoint({x: 5, y: 10});
ArkTS
class Point {
x: number = 0
y: number = 0
// 在字面量初始化之前,使用constructor()创建一个有效对象。
// 由于没有为Point定义构造函数,编译器将自动添加一个默认构造函数。
}
function getPoint(o: Point): Point {
return o;
}
// 字面量初始化需要显式定义类型
let p: Point = {x: 5, y: 10};
getPoint(p);
// getPoint接受Point类型,字面量初始化生成一个Point的新实例
getPoint({x: 5, y: 10});
相关约束
- 对象字面量不能用于类型声明
- 数组字面量必须仅包含可推断类型的元素
对象字面量不能用于类型声明
规则:arkts-no-obj-literals-as-types
级别:错误
ArkTS不支持使用对象字面量声明类型,可以使用类或者接口声明类型。
TypeScript
let o: {x: number, y: number} = {
x: 2,
y: 3
}
type S = Set<{x: number, y: number}>
ArkTS
class O {
x: number = 0
y: number = 0
}
let o: O = {x: 2, y: 3};
type S = Set<O>
相关约束
- 对象字面量必须对应某些显式声明的类或接口
- 数组字面量必须仅包含可推断类型的元素
数组字面量必须仅包含可推断类型的元素
规则:arkts-no-noninferrable-arr-literals
级别:错误
本质上,ArkTS将数组字面量的类型推断为数组所有元素的联合类型。如果其中任何一个元素的类型无法根据上下文推导出来(例如,无类型的对象字面量),则会发生编译时错误。
TypeScript
let a = [{n: 1, s: '1'}, {n: 2, s: '2'}];
ArkTS
class C {
n: number = 0
s: string = ''
}
let a1 = [{n: 1, s: '1'} as C, {n: 2, s: '2'} as C]; // a1的类型为“C[]”
let a2: C[] = [{n: 1, s: '1'}, {n: 2, s: '2'}]; // a2的类型为“C[]”
相关约束
- 对象字面量必须对应某些显式声明的类或接口
- 对象字面量不能用于类型声明
使用箭头函数而非函数表达式
规则:arkts-no-func-expressions
级别:错误
ArkTS不支持函数表达式,使用箭头函数。
TypeScript
let f = function (s: string) {
console.log(s);
}
ArkTS
let f = (s: string) => {
console.log(s);
}
使用泛型函数而非泛型箭头函数
规则:arkts-no-generic-lambdas
级别:错误
ArkTS不支持泛型箭头函数。
TypeScript
let generic_arrow_func = <T extends String> (x: T) => { return x; };
generic_arrow_func('string');
ArkTS
function generic_func<T extends String>(x: T): T {
return x;
}
generic_func<String>('string');
不支持使用类表达式
规则:arkts-no-class-literals
级别:错误
ArkTS不支持使用类表达式,必须显式声明一个类。
TypeScript
const Rectangle = class {
constructor(height: number, width: number) {
this.height = height;
this.width = width;
}
height
width
}
const rectangle = new Rectangle(0.0, 0.0);
ArkTS
class Rectangle {
constructor(height: number, width: number) {
this.height = height;
this.width = width;
}
height: number
width: number
}
const rectangle = new Rectangle(0.0, 0.0);
类不允许implements
规则:arkts-implements-only-iface
级别:错误
ArkTS不允许类被implements,只有接口可以被implements。
TypeScript
class C {
foo() {}
}
class C1 implements C {
foo() {}
}
ArkTS
interface C {
foo(): void
}
class C1 implements C {
foo() {}
}
不支持修改对象的方法
规则:arkts-no-method-reassignment
级别:错误
ArkTS不支持修改对象的方法。在静态语言中,对象的布局是确定的。一个类的所有对象实例享有同一个方法。
如果需要为某个特定的对象增加方法,可以封装函数或者使用继承的机制。
TypeScript
class C {
foo() {
console.log('foo');
}
}
function bar() {
console.log('bar');
}
let c1 = new C();
let c2 = new C();
c2.foo = bar;
c1.foo(); // foo
c2.foo(); // bar
ArkTS
class C {
foo() {
console.log('foo');
}
}
class Derived extends C {
foo() {
console.log('Extra');
super.foo();
}
}
function bar() {
console.log('bar');
}
let c1 = new C();
let c2 = new C();
c1.foo(); // foo
c2.foo(); // foo
let c3 = new Derived();
c3.foo(); // Extra foo
类型转换仅支持as T语法
规则:arkts-as-casts
级别:错误
在ArkTS中,as关键字是类型转换的唯一语法,错误的类型转换会导致编译时错误或者运行时抛出ClassCastException异常。ArkTS不支持使用<type>语法进行类型转换。
当需要将primitive类型(如number或boolean)转换成引用类型时,请使用new表达式。
TypeScript
class Shape {}
class Circle extends Shape { x: number = 5 }
class Square extends Shape { y: string = 'a' }
function createShape(): Shape {
return new Circle();
}
let c1 = <Circle> createShape();
let c2 = createShape() as Circle;
// 如果转换错误,不会产生编译时或运行时报错
let c3 = createShape() as Square;
console.log(c3.y); // undefined
// 在TS中,由于`as`关键字不会在运行时生效,所以`instanceof`的左操作数不会在运行时被装箱成引用类型
let e1 = (5.0 as Number) instanceof Number; // false
// 创建Number对象,获得预期结果:
let e2 = (new Number(5.0)) instanceof Number; // true
ArkTS
class Shape {}
class Circle extends Shape { x: number = 5 }
class Square extends Shape { y: string = 'a' }
function createShape(): Shape {
return new Circle();
}
let c2 = createShape() as Circle;
// 运行时抛出ClassCastException异常:
let c3 = createShape() as Square;
// 创建Number对象,获得预期结果:
let e2 = (new Number(5.0)) instanceof Number; // true
不支持JSX表达式
规则:arkts-no-jsx
级别:错误
不支持使用JSX。
一元运算符+、-和~仅适用于数值类型
规则:arkts-no-polymorphic-unops
级别:错误
ArkTS仅允许一元运算符用于数值类型,否则会发生编译时错误。与TypeScript不同,ArkTS不支持隐式将字符串转换成数值,必须进行显式转换。
TypeScript
let a = +5; // 5(number类型)
let b = +'5'; // 5(number类型)
let c = -5; // -5(number类型)
let d = -'5'; // -5(number类型)
let e = ~5; // -6(number类型)
let f = ~'5'; // -6(number类型)
let g = +'string'; // NaN(number类型)
function returnTen(): string {
return '-10';
}
function returnString(): string {
return 'string';
}
let x = +returnTen(); // -10(number类型)
let y = +returnString(); // NaN
ArkTS
let a = +5; // 5(number类型)
let b = +'5'; // 编译时错误
let c = -5; // -5(number类型)
let d = -'5'; // 编译时错误
let e = ~5; // -6(number类型)
let f = ~'5'; // 编译时错误
let g = +'string'; // 编译时错误
function returnTen(): string {
return '-10';
}
function returnString(): string {
return 'string';
}
let x = +returnTen(); // 编译时错误
let y = +returnString(); // 编译时错误
不支持delete运算符
规则:arkts-no-delete
级别:错误
ArkTS中,对象布局在编译时就确定了,且不能在运行时被更改。因此,删除属性的操作没有意义。
TypeScript
class Point {
x?: number = 0.0
y?: number = 0.0
}
let p = new Point();
delete p.y;
ArkTS
// 可以声明一个可空类型并使用null作为缺省值
class Point {
x: number | null = 0
y: number | null = 0
}
let p = new Point();
p.y = null;
相关约束
- 对象的属性名必须是合法的标识符
- 不支持Symbol() API
- 不支持通过索引访问字段
- 仅允许在表达式中使用typeof运算符
- 不支持in运算符
仅允许在表达式中使用typeof运算符
规则:arkts-no-type-query
级别:错误
ArkTS仅支持在表达式中使用typeof运算符,不允许使用typeof作为类型。
TypeScript
let n1 = 42;
let s1 = 'foo';
console.log(typeof n1); // 'number'
console.log(typeof s1); // 'string'
let n2: typeof n1
let s2: typeof s1
ArkTS
let n1 = 42;
let s1 = 'foo';
console.log(typeof n1); // 'number'
console.log(typeof s1); // 'string'
let n2: number
let s2: string
相关约束
- 对象的属性名必须是合法的标识符
- 不支持Symbol() API
- 不支持通过索引访问字段
- 不支持delete运算符
- 不支持in运算符
- 限制使用标准库
部分支持instanceof运算符
规则:arkts-instanceof-ref-types
级别:错误
在TypeScript中,instanceof运算符的左操作数的类型必须为any类型、对象类型,或者它是类型参数,否则结果为false。在ArkTS中,instanceof运算符的左操作数的类型必须为引用类型(例如,对象、数组或者函数),否则会发生编译时错误。此外,在ArkTS中,instanceof运算符的左操作数不能是类型,必须是对象的实例。
不支持in运算符
规则:arkts-no-in
级别:错误
由于在ArkTS中,对象布局在编译时是已知的并且在运行时无法修改,因此,不支持in运算符。如果仍需检查某些类成员是否存在,使用instanceof代替。
TypeScript
class Person {
name: string = ''
}
let p = new Person();
let b = 'name' in p; // true
ArkTS
class Person {
name: string = ''
}
let p = new Person();
let b = p instanceof Person; // true,且属性name一定存在
相关约束
- 对象的属性名必须是合法的标识符
- 不支持Symbol() API
- 不支持通过索引访问字段
- 不支持delete运算符
- 仅允许在表达式中使用typeof运算符
- 限制使用标准库
不支持解构赋值
规则:arkts-no-destruct-assignment
级别:错误
ArkTS不支持解构赋值。可使用其他替代方法,例如,使用临时变量。
TypeScript
let [one, two] = [1, 2]; // 此处需要分号
[one, two] = [two, one];
let head, tail
[head, ...tail] = [1, 2, 3, 4];
ArkTS
let arr: number[] = [1, 2];
let one = arr[0];
let two = arr[1];
let tmp = one;
one = two;
two = tmp;
let data: Number[] = [1, 2, 3, 4];
let head = data[0];
let tail: Number[] = [];
for (let i = 1; i < data.length; ++i) {
tail.push(data[i]);
}
逗号运算符,仅用在for循环语句中
规则:arkts-no-comma-outside-loops
级别:错误
为了方便理解执行顺序,在ArkTS中,逗号运算符仅适用于for循环语句中。注意与声明变量、函数参数传递时的逗号分隔符不同。
TypeScript
for (let i = 0, j = 0; i < 10; ++i, j += 2) {
// ...
}
let x = 0;
x = (++x, x++); // 1
ArkTS
for (let i = 0, j = 0; i < 10; ++i, j += 2) {
// ...
}
// 通过语句表示执行顺序,而非逗号运算符
let x = 0;
++x;
x = x++;
不支持解构变量声明
规则:arkts-no-destruct-decls
级别:错误
ArkTS不支持解构变量声明。它是一个依赖于结构兼容性的动态特性并且解构声明中的名称必须和被解构对象中的属性名称一致。
TypeScript
class Point {
x: number = 0.0
y: number = 0.0
}
function returnZeroPoint(): Point {
return new Point();
}
let {x, y} = returnZeroPoint();
ArkTS
class Point {
x: number = 0.0
y: number = 0.0
}
function returnZeroPoint(): Point {
return new Point();
}
// 创建一个局部变量来处理每个字段
let zp = returnZeroPoint();
let x = zp.x;
let y = zp.y;
不支持在catch语句标注类型
规则:arkts-no-types-in-catch
级别:错误
在TypeScript的catch语句中,只能标注any或unknown类型。由于ArkTS不支持这些类型,应省略类型标注。
TypeScript
try {
// ...
} catch (a: unknown) {
// 处理异常
}
ArkTS
try {
// ...
} catch (a) {
// 处理异常
}
相关约束
限制throw语句中表达式的类型
不支持for .. in
规则:arkts-no-for-in
级别:错误
由于在ArkTS中,对象布局在编译时是确定的、并且不能在运行时被改变,所以不支持使用for .. in迭代一个对象的属性。对于数组来说,可以使用常规的for循环。
TypeScript
let a: string[] = ['1.0', '2.0', '3.0'];
for (let i in a) {
console.log(a[i]);
}
ArkTS
let a: string[] = ['1.0', '2.0', '3.0'];
for (let i = 0; i < a.length; ++i) {
console.log(a[i]);
}
不支持映射类型
规则:arkts-no-mapped-types
级别:错误
ArkTS不支持映射类型,使用其他语法来表示相同的语义。
TypeScript
type OptionsFlags<Type> = {
[Property in keyof Type]: boolean
}
ArkTS
class C {
n: number = 0
s: string = ''
}
class CFlags {
n: boolean = false
s: boolean = false
}
不支持with语句
规则:arkts-no-with
级别:错误
ArkTS不支持with语句,使用其他语法来表示相同的语义。
TypeScript
with (Math) { // 编译时错误, 但是仍能生成JavaScript代码
let r: number = 42;
let area: number = PI * r * r;
}
ArkTS
let r: number = 42;
let area: number = Math.PI * r * r;
限制throw语句中表达式的类型
规则:arkts-limited-throw
级别:错误
ArkTS只支持抛出Error类或其派生类的实例。禁止抛出其他类型(例如number或string)的数据。
TypeScript
throw 4;
throw '';
throw new Error();
ArkTS
throw new Error();
限制省略函数返回类型标注
规则:arkts-no-implicit-return-types
级别:错误
ArkTS在部分场景中支持对函数返回类型进行推断。当return语句中的表达式是对某个函数或方法进行调用,且该函数或方法的返回类型没有被显著标注时,会出现编译时错误。在这种情况下,请标注函数返回类型。
TypeScript
// 只有在开启noImplicitAny选项时会产生编译时错误
function f(x: number) {
if (x <= 0) {
return x;
}
return g(x);
}
// 只有在开启noImplicitAny选项时会产生编译时错误
function g(x: number) {
return f(x - 1);
}
function doOperation(x: number, y: number) {
return x + y;
}
f(10);
doOperation(2, 3);
ArkTS
// 需标注返回类型:
function f(x: number): number {
if (x <= 0) {
return x;
}
return g(x);
}
// 可以省略返回类型,返回类型可以从f的类型标注推导得到
function g(x: number): number {
return f(x - 1);
}
// 可以省略返回类型
function doOperation(x: number, y: number) {
return x + y;
}
f(10);
doOperation(2, 3);