• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 从TypeScript到ArkTS的适配规则
2
3ArkTS通过规范约束了TypeScript(简称TS)中过于灵活而影响开发正确性或者给运行时带来不必要额外开销的特性。本文罗列了所有在ArkTS中限制的TS特性,并提供了重构代码的建议。ArkTS保留了TS大部分的语法特性,对于本文中没有约束的TS特性,则说明ArkTS完全支持它们。例如:ArkTS支持自定义装饰器,语法上和TS一致。按照本文提供的约束进行代码重构后的代码仍为合法有效的TS代码。
4
5**示例**
6
7包含关键字`var`的原始TypeScript代码:
8
9```typescript
10function addTen(x: number): number {
11  var ten = 10;
12  return x + ten;
13}
14```
15
16重构后的代码:
17
18```typescript
19function addTen(x: number): number {
20  let ten = 10;
21  return x + ten;
22}
23```
24
25**级别**
26
27约束分为两个级别:错误、警告。
28
29- **错误**: 必须要遵从的约束。如果不遵从该约束,将会导致程序编译失败。
30- **警告**: 推荐遵从的约束。尽管现在违反该约束不会影响编译流程,但是在将来,违反该约束可能将会导致程序编译失败。
31
32**不支持的特性**
33
34目前,不支持的特性主要包括:
35
36- 与降低运行时性能的动态类型相关的特性。
37- 需要编译器额外支持从而导致项目构建时间增加的特性。
38
39根据开发者的反馈以及更多实际场景的数据,我们将来可能进一步**缩小**不支持特性的范围。
40
41## 概述
42
43本节罗列了ArkTS不支持或部分支持的TypeScript特性。完整的列表以及详细的代码示例和重构建议,请参考[约束说明](#约束说明)。更多案例请参考[适配指导案例](arkts-more-cases.md)。
44
45### 强制使用静态类型
46
47静态类型是ArkTS最重要的特性之一。如果程序采用静态类型,即所有类型在编译时都是已知的,那么开发者就能够容易理解代码中使用了哪些数据结构。同时,由于所有类型在程序实际运行前都是已知的,编译器可以提前验证代码的正确性,从而可以减少运行时的类型检查,有助于提升性能。
48
49基于上述考虑,ArkTS中禁止使用`any`类型。
50
51**示例**
52
53```typescript
54// 不支持:
55let res: any = some_api_function('hello', 'world');
56// `res`是什么?错误代码的数字?字符串?对象?
57// 该如何处理它?
58// 支持:
59class CallResult {
60  public succeeded(): boolean { ... }
61  public errorMessage(): string { ... }
62}
63
64let res: CallResult = some_api_function('hello', 'world');
65if (!res.succeeded()) {
66  console.log('Call failed: ' + res.errorMessage());
67}
68```
69
70`any`类型在TypeScript中并不常见,只有大约1%的TypeScript代码库使用。一些代码检查工具(例如ESLint)也制定一系列规则来禁止使用`any`。因此,虽然禁止`any`将导致代码重构,但重构量很小,有助于整体性能提升。
71
72### 禁止在运行时变更对象布局
73
74为实现最佳性能,ArkTS要求在程序执行期间不能更改对象的布局。换句话说,ArkTS禁止以下行为:
75
76- 向对象中添加新的属性或方法。
77- 从对象中删除已有的属性或方法。
78- 将任意类型的值赋值给对象属性。
79
80TypeScript编译器已经禁止了许多此类操作。然而,有些操作还是有可能绕过编译器的,例如,使用`as any`转换对象的类型,或者在编译TS代码时关闭严格类型检查的配置,或者在代码中通过`@ts-ignore`忽略类型检查。
81
82在ArkTS中,严格类型检查不是可配置项。ArkTS强制进行部分严格类型检查,并通过规范禁止使用`any`类型,禁止在代码中使用`@ts-ignore`。
83
84**示例**
85
86```typescript
87class Point {
88  public x: number = 0
89  public y: number = 0
90
91  constructor(x: number, y: number) {
92    this.x = x;
93    this.y = y;
94  }
95}
96
97// 无法从对象中删除某个属性,从而确保所有Point对象都具有属性x
98let p1 = new Point(1.0, 1.0);
99delete p1.x;           // 在TypeScript和ArkTS中,都会产生编译时错误
100delete (p1 as any).x;  // 在TypeScript中不会报错;在ArkTS中会产生编译时错误
101
102// Point类没有定义命名为z的属性,在程序运行时也无法添加该属性
103let p2 = new Point(2.0, 2.0);
104p2.z = 'Label';           // 在TypeScript和ArkTS中,都会产生编译时错误
105(p2 as any).z = 'Label';   // 在TypeScript中不会报错;在ArkTS中会产生编译时错误
106
107// 类的定义确保了所有Point对象只有属性x和y,并且无法被添加其他属性
108let p3 = new Point(3.0, 3.0);
109let prop = Symbol();      // 在TypeScript中不会报错;在ArkTS中会产生编译时错误
110(p3 as any)[prop] = p3.x; // 在TypeScript中不会报错;在ArkTS中会产生编译时错误
111p3[prop] = p3.x;          // 在TypeScript和ArkTS中,都会产生编译时错误
112
113// 类的定义确保了所有Point对象的属性x和y都具有number类型,因此,无法将其他类型的值赋值给它们
114let p4 = new Point(4.0, 4.0);
115p4.x = 'Hello!';          // 在TypeScript和ArkTS中,都会产生编译时错误
116(p4 as any).x = 'Hello!'; // 在TypeScript中不会报错;在ArkTS中会产生编译时错误
117
118// 使用符合类定义的Point对象:
119function distance(p1: Point, p2: Point): number {
120  return Math.sqrt(
121    (p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y)
122  );
123}
124let p5 = new Point(5.0, 5.0);
125let p6 = new Point(6.0, 6.0);
126console.log('Distance between p5 and p6: ' + distance(p5, p6));
127```
128
129修改对象布局会影响代码的可读性以及运行时性能。从开发者的角度来说,在某处定义类,然后又在其他地方修改实际的对象布局,很容易引起困惑乃至引入错误。此外,这点还需要额外的运行时支持,增加了执行开销。这一点与静态类型的约束也冲突:既然已决定使用显式类型,为什么还需要添加或删除属性呢?
130
131当前,只有少数项目允许在运行时变更对象布局,一些常用的代码检查工具也增加了相应的限制规则。这个约束只会导致少量代码重构,但会提升性能。
132
133### 限制运算符的语义
134
135为获得更好的性能并鼓励开发者编写更清晰的代码,ArkTS限制了一些运算符的语义。详细的语义限制,请参考[约束说明](#约束说明)。
136
137**示例**
138
139```typescript
140// 一元运算符`+`只能作用于数值类型:
141let t = +42;   // 合法运算
142let s = +'42'; // 编译时错误
143```
144
145使用额外的语义重载语言运算符会增加语言规范的复杂度,而且,开发者还被迫牢记所有可能的例外情况及对应的处理规则。在某些情况下,产生一些不必要的运行时开销。
146
147当前只有不到1%的代码库使用该特性。因此,尽管限制运算符的语义需要重构代码,但重构量很小且非常容易操作,并且,通过重构能使代码更清晰、具备更高性能。
148
149### 不支持 structural typing
150
151假设两个不相关的类`T`和`U`拥有相同的`public`API:
152
153```typescript
154class T {
155  public name: string = ''
156
157  public greet(): void {
158    console.log('Hello, ' + this.name);
159  }
160}
161
162class U {
163  public name: string = ''
164
165  public greet(): void {
166    console.log('Greetings, ' + this.name);
167  }
168}
169```
170
171能把类型为`T`的值赋给类型为`U`的变量吗?
172
173```typescript
174let u: U = new T(); // 是否允许?
175```
176
177能把类型为`T`的值传递给接受类型为`U`的参数的函数吗?
178
179```typescript
180function greeter(u: U) {
181  console.log('To ' + u.name);
182  u.greet();
183}
184
185let t: T = new T();
186greeter(t); // 是否允许?
187```
188
189换句话说,我们将采取下面哪种方法呢:
190
191- `T`和`U`没有继承关系或没有`implements`相同的接口,但由于它们具有相同的`public`API,它们“在某种程度上是相等的”,所以上述两个问题的答案都是“是”;
192- `T`和`U`没有继承关系或没有`implements`相同的接口,应当始终被视为完全不同的类型,因此上述两个问题的答案都是“否”。
193
194采用第一种方法的语言支持structural typing,而采用第二种方法的语言则不支持structural typing。目前TypeScript支持structural typing,而ArkTS不支持。
195
196structural typing是否有助于生成清晰、易理解的代码,关于这一点并没有定论。那为什么ArkTS不支持structural typing呢?
197
198因为对structural typing的支持是一个重大的特性,需要在语言规范、编译器和运行时进行大量的考虑和仔细的实现。另外,由于ArkTS使用静态类型,运行时为了支持这个特性需要额外的性能开销。
199
200鉴于此,当前我们还不支持该特性。根据实际场景的需求和反馈,我们后续会重新加以考虑。更多案例和建议请参考[约束说明](#约束说明)。
201
202## 约束说明
203
204### 对象的属性名必须是合法的标识符
205
206**规则:**`arkts-identifiers-as-prop-names`
207
208**级别:错误**
209
210在ArkTS中,对象的属性名不能为数字或字符串。例外:ArkTS支持属性名为字符串字面量和枚举中的字符串值。通过属性名访问类的属性,通过数值索引访问数组元素。
211
212**TypeScript**
213
214```typescript
215var x = { 'name': 'x', 2: '3' };
216
217console.log(x['name']);
218console.log(x[2]);
219```
220
221**ArkTS**
222
223```typescript
224class X {
225  public name: string = ''
226}
227let x: X = { name: 'x' };
228console.log(x.name);
229
230let y = ['a', 'b', 'c'];
231console.log(y[2]);
232
233// 在需要通过非标识符(即不同类型的key)获取数据的场景中,使用Map<Object, some_type>。
234let z = new Map<Object, string>();
235z.set('name', '1');
236z.set(2, '2');
237console.log(z.get('name'));
238console.log(z.get(2));
239
240enum Test {
241  A = 'aaa',
242  B = 'bbb'
243}
244
245let obj: Record<string, number> = {
246  [Test.A]: 1,   // 枚举中的字符串值
247  [Test.B]: 2,   // 枚举中的字符串值
248  ['value']: 3   // 字符串字面量
249}
250```
251
252**相关约束**
253
254* 不支持Symbol() API
255* 不支持通过索引访问字段
256* 不支持delete运算符
257* 仅允许在表达式中使用typeof运算符
258* 不支持in运算符
259* 限制使用标准库
260
261
262### 不支持`Symbol()`API
263
264**规则:**`arkts-no-symbol`
265
266**级别:错误**
267
268TypeScript中的`Symbol()`API用于在运行时生成唯一的属性名称。由于该API的常见使用场景在静态类型语言中没有意义,因此,ArkTS不支持`Symbol()`API。在ArkTS中,对象布局在编译时就确定了,且不能在运行时被更改。
269
270ArkTS只支持`Symbol.iterator`。
271
272**相关约束**
273
274* 仅支持属性名为标识符的对象
275* 不支持通过索引访问字段
276* 不支持delete运算符
277* 仅允许在表达式中使用typeof运算符
278* 不支持in运算符
279* 限制使用标准库
280
281### 不支持以`#`开头的私有字段
282
283**规则:**`arkts-no-private-identifiers`
284
285**级别:错误**
286
287ArkTS不支持使用`#`符号开头声明的私有字段。改用`private`关键字。
288
289**TypeScript**
290
291```typescript
292class C {
293  #foo: number = 42
294}
295```
296
297**ArkTS**
298
299```typescript
300class C {
301  private foo: number = 42
302}
303```
304
305### 类型、命名空间的命名必须唯一
306
307**规则:**`arkts-unique-names`
308
309**级别:错误**
310
311类型(类、接口、枚举)、命名空间的命名必须唯一,且与其他名称(例如:变量名、函数名)不同。
312
313**TypeScript**
314
315```typescript
316let X: string
317type X = number[] // 类型的别名与变量同名
318```
319
320**ArkTS**
321
322```typescript
323let X: string
324type T = number[] // 为避免名称冲突,此处不允许使用X
325```
326
327### 使用`let`而非`var`
328
329**规则:**`arkts-no-var`
330
331**级别:错误**
332
333`let`关键字可以在块级作用域中声明变量,帮助程序员避免错误。因此,ArkTS不支持`var`,请使用`let`声明变量。
334
335**TypeScript**
336
337```typescript
338function f(shouldInitialize: boolean) {
339  if (shouldInitialize) {
340     var x = 'b';
341  }
342  return x;
343}
344
345console.log(f(true));  // b
346console.log(f(false)); // undefined
347
348let upper_let = 0;
349{
350  var scoped_var = 0;
351  let scoped_let = 0;
352  upper_let = 5;
353}
354scoped_var = 5; // 可见
355scoped_let = 5; // 编译时错误
356```
357
358**ArkTS**
359
360```typescript
361function f(shouldInitialize: boolean): string {
362  let x: string = 'a';
363  if (shouldInitialize) {
364    x = 'b';
365  }
366  return x;
367}
368
369console.log(f(true));  // b
370console.log(f(false)); // a
371
372let upper_let = 0;
373let scoped_var = 0;
374{
375  let scoped_let = 0;
376  upper_let = 5;
377}
378scoped_var = 5;
379scoped_let = 5; //编译时错误
380```
381
382### 使用具体的类型而非`any`或`unknown`
383
384**规则:**`arkts-no-any-unknown`
385
386**级别:错误**
387
388ArkTS不支持`any`和`unknown`类型。显式指定具体类型。
389
390**TypeScript**
391
392```typescript
393let value1: any
394value1 = true;
395value1 = 42;
396
397let value2: unknown
398value2 = true;
399value2 = 42;
400```
401
402**ArkTS**
403
404```typescript
405let value_b: boolean = true; // 或者 let value_b = true
406let value_n: number = 42; // 或者 let value_n = 42
407let value_o1: Object = true;
408let value_o2: Object = 42;
409```
410
411**相关约束**
412
413强制进行严格类型检查
414
415### 使用`class`而非具有call signature的类型
416
417**规则:**`arkts-no-call-signatures`
418
419**级别:错误**
420
421ArkTS不支持对象类型中包含call signature。
422
423**TypeScript**
424
425```typescript
426type DescribableFunction = {
427  description: string
428  (someArg: string): string // call signature
429}
430
431function doSomething(fn: DescribableFunction): void {
432  console.log(fn.description + ' returned ' + fn(6));
433}
434```
435
436**ArkTS**
437
438```typescript
439class DescribableFunction {
440  description: string
441  public invoke(someArg: string): string {
442    return someArg;
443  }
444  constructor() {
445    this.description = 'desc';
446  }
447}
448
449function doSomething(fn: DescribableFunction): void {
450  console.log(fn.description + ' returned ' + fn.invoke(6));
451}
452
453doSomething(new DescribableFunction());
454```
455
456**相关约束**
457
458使用class而非具有构造签名的类型
459
460### 使用`class`而非具有构造签名的类型
461
462**规则:**`arkts-no-ctor-signatures-type`
463
464**级别:错误**
465
466ArkTS不支持对象类型中的构造签名。改用类。
467
468**TypeScript**
469
470```typescript
471class SomeObject {}
472
473type SomeConstructor = {
474  new (s: string): SomeObject
475}
476
477function fn(ctor: SomeConstructor) {
478  return new ctor('hello');
479}
480```
481
482**ArkTS**
483
484```typescript
485class SomeObject {
486  public f: string
487  constructor (s: string) {
488    this.f = s;
489  }
490}
491
492function fn(s: string): SomeObject {
493  return new SomeObject(s);
494}
495```
496
497**相关约束**
498
499使用class而非具有call signature的类型
500
501### 仅支持一个静态块
502
503**规则:**`arkts-no-multiple-static-blocks`
504
505**级别:错误**
506
507ArkTS不允许类中有多个静态块,如果存在多个静态块语句,请合并到一个静态块中。
508
509**TypeScript**
510
511```typescript
512class C {
513  static s: string
514
515  static {
516    C.s = 'aa'
517  }
518  static {
519    C.s = C.s + 'bb'
520  }
521}
522```
523
524**ArkTS**
525
526```typescript
527class C {
528  static s: string
529
530  static {
531    C.s = 'aa'
532    C.s = C.s + 'bb'
533  }
534}
535```
536
537**说明**
538
539当前不支持静态块的语法。支持该语法后,在.ets文件中使用静态块须遵循本约束。
540
541### 不支持index signature
542
543**规则:**`arkts-no-indexed-signatures`
544
545**级别:错误**
546
547ArkTS不允许index signature,改用数组。
548
549**TypeScript**
550
551```typescript
552// 带index signature的接口:
553interface StringArray {
554  [index: number]: string
555}
556
557function getStringArray(): StringArray {
558  return ['a', 'b', 'c'];
559}
560
561const myArray: StringArray = getStringArray();
562const secondItem = myArray[1];
563```
564
565**ArkTS**
566
567```typescript
568class X {
569  public f: string[] = []
570}
571
572let myArray: X = new X();
573const secondItem = myArray.f[1];
574```
575
576### 使用继承而非intersection type
577
578**规则:**`arkts-no-intersection-types`
579
580**级别:错误**
581
582目前ArkTS不支持intersection type,可以使用继承作为替代方案。
583
584**TypeScript**
585
586```typescript
587interface Identity {
588  id: number
589  name: string
590}
591
592interface Contact {
593  email: string
594  phoneNumber: string
595}
596
597type Employee = Identity & Contact
598```
599
600**ArkTS**
601
602```typescript
603interface Identity {
604  id: number
605  name: string
606}
607
608interface Contact {
609  email: string
610  phoneNumber: string
611}
612
613interface Employee extends Identity,  Contact {}
614```
615
616### 不支持`this`类型
617
618**规则:**`arkts-no-typing-with-this`
619
620**级别:错误**
621
622ArkTS不支持`this`类型,改用显式具体类型。
623
624**TypeScript**
625
626```typescript
627interface ListItem {
628  getHead(): this
629}
630
631class C {
632  n: number = 0
633
634  m(c: this) {
635    // ...
636  }
637}
638```
639
640**ArkTS**
641
642```typescript
643interface ListItem {
644  getHead(): ListItem
645}
646
647class C {
648  n: number = 0
649
650  m(c: C) {
651    // ...
652  }
653}
654```
655
656### 不支持条件类型
657
658**规则:**`arkts-no-conditional-types`
659
660**级别:错误**
661
662ArkTS不支持条件类型别名,引入带显式约束的新类型,或使用`Object`重写逻辑。
663不支持`infer`关键字。
664
665**TypeScript**
666
667```typescript
668type X<T> = T extends number ? T: never
669type Y<T> = T extends Array<infer Item> ? Item: never
670```
671
672**ArkTS**
673
674```typescript
675// 在类型别名中提供显式约束
676type X1<T extends number> = T
677
678// 用Object重写,类型控制较少,需要更多的类型检查以确保安全
679type X2<T> = Object
680
681// Item必须作为泛型参数使用,并能正确实例化
682type YI<Item, T extends Array<Item>> = Item
683```
684
685### 不支持在`constructor`中声明字段
686
687**规则:**`arkts-no-ctor-prop-decls`
688
689**级别:错误**
690
691ArkTS不支持在`constructor`中声明类字段。在`class`中声明这些字段。
692
693**TypeScript**
694
695```typescript
696class Person {
697  constructor(
698    protected ssn: string,
699    private firstName: string,
700    private lastName: string
701  ) {
702    this.ssn = ssn;
703    this.firstName = firstName;
704    this.lastName = lastName;
705  }
706
707  getFullName(): string {
708    return this.firstName + ' ' + this.lastName;
709  }
710}
711```
712
713**ArkTS**
714
715```typescript
716class Person {
717  protected ssn: string
718  private firstName: string
719  private lastName: string
720
721  constructor(ssn: string, firstName: string, lastName: string) {
722    this.ssn = ssn;
723    this.firstName = firstName;
724    this.lastName = lastName;
725  }
726
727  getFullName(): string {
728    return this.firstName + ' ' + this.lastName;
729  }
730}
731```
732
733### 接口中不支持构造签名
734
735**规则:**`arkts-no-ctor-signatures-iface`
736
737**级别:错误**
738
739ArkTS不支持在接口中使用构造签名。改用函数或者方法。
740
741**TypeScript**
742
743```typescript
744interface I {
745  new (s: string): I
746}
747
748function fn(i: I) {
749  return new i('hello');
750}
751```
752
753**ArkTS**
754
755```typescript
756interface I {
757  create(s: string): I
758}
759
760function fn(i: I) {
761  return i.create('hello');
762}
763```
764
765**相关约束**
766
767使用class而非具有构造签名的类型
768
769### 不支持索引访问类型
770
771**规则:**`arkts-no-aliases-by-index`
772
773**级别:错误**
774
775ArkTS不支持索引访问类型。
776
777### 不支持通过索引访问字段
778
779**规则:**`arkts-no-props-by-index`
780
781**级别:错误**
782
783ArkTS不支持动态声明字段,不支持动态访问字段。只能访问已在类中声明或者继承可见的字段,访问其他字段将会造成编译时错误。
784使用点操作符访问字段,例如(`obj.field`),不支持索引访问(`obj[field]`)。
785ArkTS支持通过索引访问`TypedArray`(例如`Int32Array`)中的元素。
786
787**TypeScript**
788
789```typescript
790class Point {
791  x: string = ''
792  y: string = ''
793}
794let p: Point = {x: '1', y: '2'};
795console.log(p['x']);
796
797class Person {
798  name: string = ''
799  age: number = 0;
800  [key: string]: string | number
801}
802
803let person: Person = {
804  name: 'John',
805  age: 30,
806  email: '***@example.com',
807  phoneNumber: '18*********',
808}
809```
810
811**ArkTS**
812
813```typescript
814class Point {
815  x: string = ''
816  y: string = ''
817}
818let p: Point = {x: '1', y: '2'};
819console.log(p.x);
820
821class Person {
822  name: string
823  age: number
824  email: string
825  phoneNumber: string
826
827  constructor(name: string, age: number, email: string,
828        phoneNumber: string) {
829    this.name = name;
830    this.age = age;
831    this.email = email;
832    this.phoneNumber = phoneNumber;
833  }
834}
835
836let person = new Person('John', 30, '***@example.com', '18*********');
837console.log(person['name']);     // 编译时错误
838console.log(person.unknownProperty); // 编译时错误
839
840let arr = new Int32Array(1);
841arr[0];
842```
843
844### 不支持structural typing
845
846**规则:**`arkts-no-structural-typing`
847
848**级别:错误**
849
850ArkTS不支持structural typing,编译器无法比较两种类型的`public`API并决定它们是否相同。使用其他机制,例如继承、接口或类型别名。
851
852**TypeScript**
853
854```typescript
855interface I1 {
856  f(): string
857}
858
859interface I2 { // I2等价于I1
860  f(): string
861}
862
863class X {
864  n: number = 0
865  s: string = ''
866}
867
868class Y { // Y等价于X
869  n: number = 0
870  s: string = ''
871}
872
873let x = new X();
874let y = new Y();
875
876console.log('Assign X to Y');
877y = x;
878
879console.log('Assign Y to X');
880x = y;
881
882function foo(x: X) {
883  console.log(x.n + x.s);
884}
885
886// 由于X和Y的API是等价的,所以X和Y是等价的
887foo(new X());
888foo(new Y());
889```
890
891**ArkTS**
892
893```typescript
894interface I1 {
895  f(): string
896}
897
898type I2 = I1 // I2是I1的别名
899
900class B {
901  n: number = 0
902  s: string = ''
903}
904
905// D是B的继承类,构建了子类型和父类型的关系
906class D extends B {
907  constructor() {
908    super()
909  }
910}
911
912let b = new B();
913let d = new D();
914
915console.log('Assign D to B');
916b = d; // 合法赋值,因为B是D的父类
917
918// 将b赋值给d将会引起编译时错误
919// d = b
920
921interface Z {
922   n: number
923   s: string
924}
925
926// 类X implements 接口Z,构建了X和Y的关系
927class X implements Z {
928  n: number = 0
929  s: string = ''
930}
931
932// 类Y implements 接口Z,构建了X和Y的关系
933class Y implements Z {
934  n: number = 0
935  s: string = ''
936}
937
938let x: Z = new X();
939let y: Z = new Y();
940
941console.log('Assign X to Y');
942y = x // 合法赋值,它们是相同的类型
943
944console.log('Assign Y to X');
945x = y // 合法赋值,它们是相同的类型
946
947function foo(c: Z): void {
948  console.log(c.n + c.s);
949}
950
951// 类X和类Y implement 相同的接口,因此下面的两个函数调用都是合法的
952foo(new X());
953foo(new Y());
954```
955
956### 需要显式标注泛型函数类型实参
957
958**规则:**`arkts-no-inferred-generic-params`
959
960**级别:错误**
961
962如果可以从传递给泛型函数的参数中推断出具体类型,ArkTS允许省略泛型类型实参。否则,省略泛型类型实参会发生编译时错误。
963禁止仅基于泛型函数返回类型推断泛型类型参数。
964
965**TypeScript**
966
967```typescript
968function choose<T>(x: T, y: T): T {
969  return Math.random() < 0.5 ? x: y;
970}
971
972let x = choose(10, 20);   // 推断choose<number>(...)
973let y = choose('10', 20); // 编译时错误
974
975function greet<T>(): T {
976  return 'Hello' as T;
977}
978let z = greet() // T的类型被推断为“unknown”
979```
980
981**ArkTS**
982
983```typescript
984function choose<T>(x: T, y: T): T {
985  return Math.random() < 0.5 ? x: y;
986}
987
988let x = choose(10, 20);   // 推断choose<number>(...)
989let y = choose('10', 20); // 编译时错误
990
991function greet<T>(): T {
992  return 'Hello' as T;
993}
994let z = greet<string>();
995```
996
997### 需要显式标注对象字面量的类型
998
999**规则:**`arkts-no-untyped-obj-literals`
1000
1001**级别:错误**
1002
1003在ArkTS中,需要显式标注对象字面量的类型,否则,将发生编译时错误。在某些场景下,编译器可以根据上下文推断出字面量的类型。
1004
1005在以下上下文中不支持使用字面量初始化类和接口:
1006
1007* 初始化具有`any`、`Object`或`object`类型的任何对象
1008* 初始化带有方法的类或接口
1009* 初始化包含自定义含参数的构造函数的类
1010* 初始化带`readonly`字段的类
1011
1012**例子1**
1013
1014**TypeScript**
1015
1016```typescript
1017let o1 = {n: 42, s: 'foo'};
1018let o2: Object = {n: 42, s: 'foo'};
1019let o3: object = {n: 42, s: 'foo'};
1020
1021let oo: Object[] = [{n: 1, s: '1'}, {n: 2, s: '2'}];
1022```
1023
1024**ArkTS**
1025
1026```typescript
1027class C1 {
1028  n: number = 0
1029  s: string = ''
1030}
1031
1032let o1: C1 = {n: 42, s: 'foo'};
1033let o2: C1 = {n: 42, s: 'foo'};
1034let o3: C1 = {n: 42, s: 'foo'};
1035
1036let oo: C1[] = [{n: 1, s: '1'}, {n: 2, s: '2'}];
1037```
1038
1039**例子2**
1040
1041**TypeScript**
1042
1043```typescript
1044class C2 {
1045  s: string
1046  constructor(s: string) {
1047    this.s = 's =' + s;
1048  }
1049}
1050let o4: C2 = {s: 'foo'};
1051```
1052
1053**ArkTS**
1054
1055```typescript
1056class C2 {
1057  s: string
1058  constructor(s: string) {
1059    this.s = 's =' + s;
1060  }
1061}
1062let o4 = new C2('foo');
1063```
1064
1065**例子3**
1066
1067**TypeScript**
1068
1069```typescript
1070class C3 {
1071  readonly n: number = 0
1072  readonly s: string = ''
1073}
1074let o5: C3 = {n: 42, s: 'foo'};
1075```
1076
1077**ArkTS**
1078
1079```typescript
1080class C3 {
1081  n: number = 0
1082  s: string = ''
1083}
1084let o5: C3 = {n: 42, s: 'foo'};
1085```
1086
1087**例子4**
1088
1089**TypeScript**
1090
1091```typescript
1092abstract class A {}
1093let o6: A = {};
1094```
1095
1096**ArkTS**
1097
1098```typescript
1099abstract class A {}
1100class C extends A {}
1101let o6: C = {}; // 或 let o6: C = new C()
1102```
1103
1104**例子5**
1105
1106**TypeScript**
1107
1108```typescript
1109class C4 {
1110  n: number = 0
1111  s: string = ''
1112  f() {
1113    console.log('Hello');
1114  }
1115}
1116let o7: C4 = {n: 42, s: 'foo', f: () => {}};
1117```
1118
1119**ArkTS**
1120
1121```typescript
1122class C4 {
1123  n: number = 0
1124  s: string = ''
1125  f() {
1126    console.log('Hello');
1127  }
1128}
1129let o7 = new C4();
1130o7.n = 42;
1131o7.s = 'foo';
1132```
1133
1134**例子6**
1135
1136**TypeScript**
1137
1138```typescript
1139class Point {
1140  x: number = 0
1141  y: number = 0
1142}
1143
1144function id_x_y(o: Point): Point {
1145  return o;
1146}
1147
1148// TS支持structural typing,可以推断p的类型为Point
1149let p = {x: 5, y: 10};
1150id_x_y(p);
1151
1152// 可通过上下文推断出对象字面量的类型为Point
1153id_x_y({x: 5, y: 10});
1154```
1155
1156**ArkTS**
1157
1158```typescript
1159class Point {
1160  x: number = 0
1161  y: number = 0
1162
1163  // 在字面量初始化之前,使用constructor()创建一个有效对象。
1164  // 由于没有为Point定义构造函数,编译器将自动添加一个默认构造函数。
1165}
1166
1167function id_x_y(o: Point): Point {
1168  return o;
1169}
1170
1171// 字面量初始化需要显式定义类型
1172let p: Point = {x: 5, y: 10};
1173id_x_y(p);
1174
1175// id_x_y接受Point类型,字面量初始化生成一个Point的新实例
1176id_x_y({x: 5, y: 10});
1177```
1178
1179**相关约束**
1180
1181* 对象字面量不能用于类型声明
1182* 数组字面量必须仅包含可推断类型的元素
1183
1184### 对象字面量不能用于类型声明
1185
1186**规则:**`arkts-no-obj-literals-as-types`
1187
1188**级别:错误**
1189
1190ArkTS不支持使用对象字面量声明类型,可以使用类或者接口声明类型。
1191
1192**TypeScript**
1193
1194```typescript
1195let o: {x: number, y: number} = {
1196  x: 2,
1197  y: 3
1198}
1199
1200type S = Set<{x: number, y: number}>
1201```
1202
1203**ArkTS**
1204
1205```typescript
1206class O {
1207  x: number = 0
1208  y: number = 0
1209}
1210
1211let o: O = {x: 2, y: 3};
1212
1213type S = Set<O>
1214```
1215
1216**相关约束**
1217
1218* 对象字面量必须对应某些显式声明的类或接口
1219* 数组字面量必须仅包含可推断类型的元素
1220
1221### 数组字面量必须仅包含可推断类型的元素
1222
1223**规则:**`arkts-no-noninferrable-arr-literals`
1224
1225**级别:错误**
1226
1227本质上,ArkTS将数组字面量的类型推断为数组所有元素的联合类型。如果其中任何一个元素的类型无法根据上下文推导出来(例如,无类型的对象字面量),则会发生编译时错误。
1228
1229**TypeScript**
1230
1231```typescript
1232let a = [{n: 1, s: '1'}, {n: 2, s: '2'}];
1233```
1234
1235**ArkTS**
1236
1237```typescript
1238class C {
1239  n: number = 0
1240  s: string = ''
1241}
1242
1243let a1 = [{n: 1, s: '1'} as C, {n: 2, s: '2'} as C]; // a1的类型为“C[]”
1244let a2: C[] = [{n: 1, s: '1'}, {n: 2, s: '2'}];    // a2的类型为“C[]”
1245```
1246
1247**相关约束**
1248* 对象字面量必须对应某些显式声明的类或接口
1249* 对象字面量不能用于类型声明
1250
1251### 使用箭头函数而非函数表达式
1252
1253**规则:**`arkts-no-func-expressions`
1254
1255**级别:错误**
1256
1257ArkTS不支持函数表达式,使用箭头函数。
1258
1259**TypeScript**
1260
1261```typescript
1262let f = function (s: string) {
1263  console.log(s);
1264}
1265```
1266
1267**ArkTS**
1268
1269```typescript
1270let f = (s: string) => {
1271  console.log(s);
1272}
1273```
1274
1275### 使用泛型函数而非泛型箭头函数
1276
1277**规则:**`arkts-no-generic-lambdas`
1278
1279**级别:错误**
1280
1281ArkTS不支持泛型箭头函数。
1282
1283**TypeScript**
1284
1285```typescript
1286let generic_arrow_func = <T extends String> (x: T) => { return x; };
1287
1288generic_arrow_func('string');
1289```
1290
1291**ArkTS**
1292
1293```typescript
1294function generic_func<T extends String>(x: T): T {
1295  return x;
1296}
1297
1298generic_func<String>('string');
1299```
1300
1301### 不支持使用类表达式
1302
1303**规则:**`arkts-no-class-literals`
1304
1305**级别:错误**
1306
1307ArkTS不支持使用类表达式,必须显式声明一个类。
1308
1309**TypeScript**
1310
1311```typescript
1312const Rectangle = class {
1313  constructor(height: number, width: number) {
1314    this.height = height;
1315    this.width = width;
1316  }
1317
1318  height
1319  width
1320}
1321
1322const rectangle = new Rectangle(0.0, 0.0);
1323```
1324
1325**ArkTS**
1326
1327```typescript
1328class Rectangle {
1329  constructor(height: number, width: number) {
1330    this.height = height;
1331    this.width = width;
1332  }
1333
1334  height: number
1335  width: number
1336}
1337
1338const rectangle = new Rectangle(0.0, 0.0);
1339```
1340
1341### 类不允许`implements`
1342
1343**规则:**`arkts-implements-only-iface`
1344
1345**级别:错误**
1346
1347ArkTS不允许类被`implements`,只有接口可以被`implements`。
1348
1349**TypeScript**
1350
1351```typescript
1352class C {
1353  foo() {}
1354}
1355
1356class C1 implements C {
1357  foo() {}
1358}
1359```
1360
1361**ArkTS**
1362
1363```typescript
1364interface C {
1365  foo(): void
1366}
1367
1368class C1 implements C {
1369  foo() {}
1370}
1371```
1372
1373### 不支持修改对象的方法
1374
1375**规则:**`arkts-no-method-reassignment`
1376
1377**级别:错误**
1378
1379ArkTS不支持修改对象的方法。在静态语言中,对象的布局是确定的。一个类的所有对象实例享有同一个方法。
1380如果需要为某个特定的对象增加方法,可以封装函数或者使用继承的机制。
1381
1382**TypeScript**
1383
1384```typescript
1385class C {
1386  foo() {
1387    console.log('foo');
1388  }
1389}
1390
1391function bar() {
1392  console.log('bar');
1393}
1394
1395let c1 = new C();
1396let c2 = new C();
1397c2.foo = bar;
1398
1399c1.foo(); // foo
1400c2.foo(); // bar
1401```
1402
1403**ArkTS**
1404
1405```typescript
1406class C {
1407  foo() {
1408    console.log('foo');
1409  }
1410}
1411
1412class Derived extends C {
1413  foo() {
1414    console.log('Extra');
1415    super.foo();
1416  }
1417}
1418
1419function bar() {
1420  console.log('bar');
1421}
1422
1423let c1 = new C();
1424let c2 = new C();
1425c1.foo(); // foo
1426c2.foo(); // foo
1427
1428let c3 = new Derived();
1429c3.foo(); // Extra foo
1430```
1431
1432### 类型转换仅支持`as T`语法
1433
1434**规则:**`arkts-as-casts`
1435
1436**级别:错误**
1437
1438在ArkTS中,`as`关键字是类型转换的唯一语法,错误的类型转换会导致编译时错误或者运行时抛出`ClassCastException`异常。ArkTS不支持使用`<type>`语法进行类型转换。
1439
1440当需要将`primitive`类型(如`number`或`boolean`)转换成引用类型时,请使用`new`表达式。
1441
1442**TypeScript**
1443
1444```typescript
1445class Shape {}
1446class Circle extends Shape { x: number = 5 }
1447class Square extends Shape { y: string = 'a' }
1448
1449function createShape(): Shape {
1450  return new Circle();
1451}
1452
1453let c1 = <Circle> createShape();
1454
1455let c2 = createShape() as Circle;
1456
1457// 如果转换错误,不会产生编译时或运行时报错
1458let c3 = createShape() as Square;
1459console.log(c3.y); // undefined
1460
1461// 在TS中,由于`as`关键字不会在运行时生效,所以`instanceof`的左操作数不会在运行时被装箱成引用类型
1462let e1 = (5.0 as Number) instanceof Number; // false
1463
1464// 创建Number对象,获得预期结果:
1465let e2 = (new Number(5.0)) instanceof Number; // true
1466```
1467
1468**ArkTS**
1469
1470```typescript
1471class Shape {}
1472class Circle extends Shape { x: number = 5 }
1473class Square extends Shape { y: string = 'a' }
1474
1475function createShape(): Shape {
1476  return new Circle();
1477}
1478
1479let c2 = createShape() as Circle;
1480
1481// 运行时抛出ClassCastException异常:
1482let c3 = createShape() as Square;
1483
1484// 创建Number对象,获得预期结果:
1485let e2 = (new Number(5.0)) instanceof Number; // true
1486```
1487
1488### 不支持JSX表达式
1489
1490**规则:**`arkts-no-jsx`
1491
1492**级别:错误**
1493
1494不支持使用JSX。
1495
1496### 一元运算符`+`、`-`和`~`仅适用于数值类型
1497
1498**规则:**`arkts-no-polymorphic-unops`
1499
1500**级别:错误**
1501
1502ArkTS仅允许一元运算符用于数值类型,否则会发生编译时错误。与TypeScript不同,ArkTS不支持隐式将字符串转换成数值,必须进行显式转换。
1503
1504**TypeScript**
1505
1506```typescript
1507let a = +5;    // 5(number类型)
1508let b = +'5';    // 5(number类型)
1509let c = -5;    // -5(number类型)
1510let d = -'5';    // -5(number类型)
1511let e = ~5;    // -6(number类型)
1512let f = ~'5';    // -6(number类型)
1513let g = +'string'; // NaN(number类型)
1514
1515function returnTen(): string {
1516  return '-10';
1517}
1518
1519function returnString(): string {
1520  return 'string';
1521}
1522
1523let x = +returnTen();  // -10(number类型)
1524let y = +returnString(); // NaN
1525```
1526
1527**ArkTS**
1528
1529```typescript
1530let a = +5;    // 5(number类型)
1531let b = +'5';    // 编译时错误
1532let c = -5;    // -5(number类型)
1533let d = -'5';    // 编译时错误
1534let e = ~5;    // -6(number类型)
1535let f = ~'5';    // 编译时错误
1536let g = +'string'; // 编译时错误
1537
1538function returnTen(): string {
1539  return '-10';
1540}
1541
1542function returnString(): string {
1543  return 'string';
1544}
1545
1546let x = +returnTen();  // 编译时错误
1547let y = +returnString(); // 编译时错误
1548```
1549
1550### 不支持`delete`运算符
1551
1552**规则:**`arkts-no-delete`
1553
1554**级别:错误**
1555
1556ArkTS中,对象布局在编译时就确定了,且不能在运行时被更改。因此,删除属性的操作没有意义。
1557
1558**TypeScript**
1559
1560```typescript
1561class Point {
1562  x?: number = 0.0
1563  y?: number = 0.0
1564}
1565
1566let p = new Point();
1567delete p.y;
1568```
1569
1570**ArkTS**
1571
1572```typescript
1573// 可以声明一个可空类型并使用null作为缺省值
1574class Point {
1575  x: number | null = 0
1576  y: number | null = 0
1577}
1578
1579let p = new Point();
1580p.y = null;
1581```
1582
1583**相关约束**
1584
1585* 对象的属性名必须是合法的标识符
1586* 不支持Symbol() API
1587* 不支持通过索引访问字段
1588* 仅允许在表达式中使用typeof运算符
1589* 不支持in运算符
1590
1591### 仅允许在表达式中使用`typeof`运算符
1592
1593**规则:**`arkts-no-type-query`
1594
1595**级别:错误**
1596
1597ArkTS仅支持在表达式中使用`typeof`运算符,不允许使用`typeof`作为类型。
1598
1599**TypeScript**
1600
1601```typescript
1602let n1 = 42;
1603let s1 = 'foo';
1604console.log(typeof n1); // 'number'
1605console.log(typeof s1); // 'string'
1606let n2: typeof n1
1607let s2: typeof s1
1608```
1609
1610**ArkTS**
1611
1612```typescript
1613let n1 = 42;
1614let s1 = 'foo';
1615console.log(typeof n1); // 'number'
1616console.log(typeof s1); // 'string'
1617let n2: number
1618let s2: string
1619```
1620
1621**相关约束**
1622
1623* 对象的属性名必须是合法的标识符
1624* 不支持Symbol() API
1625* 不支持通过索引访问字段
1626* 不支持delete运算符
1627* 不支持in运算符
1628* 限制使用标准库
1629
1630### 部分支持`instanceof`运算符
1631
1632**规则:**`arkts-instanceof-ref-types`
1633
1634**级别:错误**
1635
1636在TypeScript中,`instanceof`运算符的左操作数的类型必须为`any`类型、对象类型,或者它是类型参数,否则结果为`false`。在ArkTS中,`instanceof`运算符的左操作数的类型必须为引用类型(例如,对象、数组或者函数),否则会发生编译时错误。此外,在ArkTS中,`instanceof`运算符的左操作数不能是类型,必须是对象的实例。
1637
1638### 不支持`in`运算符
1639
1640**规则:**`arkts-no-in`
1641
1642**级别:错误**
1643
1644由于在ArkTS中,对象布局在编译时是已知的并且在运行时无法修改,因此,不支持`in`运算符。如果仍需检查某些类成员是否存在,使用`instanceof`代替。
1645
1646**TypeScript**
1647
1648```typescript
1649class Person {
1650  name: string = ''
1651}
1652let p = new Person();
1653
1654let b = 'name' in p; // true
1655```
1656
1657**ArkTS**
1658
1659```typescript
1660class Person {
1661  name: string = ''
1662}
1663let p = new Person();
1664
1665let b = p instanceof Person; // true,且属性name一定存在
1666```
1667
1668**相关约束**
1669
1670* 对象的属性名必须是合法的标识符
1671* 不支持Symbol() API
1672* 不支持通过索引访问字段
1673* 不支持delete运算符
1674* 仅允许在表达式中使用typeof运算符
1675* 限制使用标准库
1676
1677### 不支持解构赋值
1678
1679**规则:**`arkts-no-destruct-assignment`
1680
1681**级别:错误**
1682
1683ArkTS不支持解构赋值。可使用其他替代方法,例如,使用临时变量。
1684
1685**TypeScript**
1686
1687```typescript
1688let [one, two] = [1, 2]; // 此处需要分号
1689[one, two] = [two, one];
1690
1691let head, tail
1692[head, ...tail] = [1, 2, 3, 4];
1693```
1694
1695**ArkTS**
1696
1697```typescript
1698let arr: number[] = [1, 2];
1699let one = arr[0];
1700let two = arr[1];
1701
1702let tmp = one;
1703one = two;
1704two = tmp;
1705
1706let data: Number[] = [1, 2, 3, 4];
1707let head = data[0];
1708let tail: Number[] = [];
1709for (let i = 1; i < data.length; ++i) {
1710  tail.push(data[i]);
1711}
1712```
1713
1714### 逗号运算符`,`仅用在`for`循环语句中
1715
1716**规则:**`arkts-no-comma-outside-loops`
1717
1718**级别:错误**
1719
1720为了方便理解执行顺序,在ArkTS中,逗号运算符仅适用于`for`循环语句中。注意与声明变量、函数参数传递时的逗号分隔符不同。
1721
1722**TypeScript**
1723
1724```typescript
1725for (let i = 0, j = 0; i < 10; ++i, j += 2) {
1726  // ...
1727}
1728
1729let x = 0;
1730x = (++x, x++); // 1
1731```
1732
1733**ArkTS**
1734
1735```typescript
1736for (let i = 0, j = 0; i < 10; ++i, j += 2) {
1737  // ...
1738}
1739
1740// 通过语句表示执行顺序,而非逗号运算符
1741let x = 0;
1742++x;
1743x = x++;
1744```
1745
1746### 不支持解构变量声明
1747
1748**规则:**`arkts-no-destruct-decls`
1749
1750**级别:错误**
1751
1752ArkTS不支持解构变量声明。它是一个依赖于结构兼容性的动态特性并且解构声明中的名称必须和被解构对象中的属性名称一致。
1753
1754**TypeScript**
1755
1756```typescript
1757class Point {
1758  x: number = 0.0
1759  y: number = 0.0
1760}
1761
1762function returnZeroPoint(): Point {
1763  return new Point();
1764}
1765
1766let {x, y} = returnZeroPoint();
1767```
1768
1769**ArkTS**
1770
1771```typescript
1772class Point {
1773  x: number = 0.0
1774  y: number = 0.0
1775}
1776
1777function returnZeroPoint(): Point {
1778  return new Point();
1779}
1780
1781// 创建一个局部变量来处理每个字段
1782let zp = returnZeroPoint();
1783let x = zp.x;
1784let y = zp.y;
1785```
1786
1787### 不支持在catch语句标注类型
1788
1789**规则:**`arkts-no-types-in-catch`
1790
1791**级别:错误**
1792
1793在TypeScript的catch语句中,只能标注`any`或`unknown`类型。由于ArkTS不支持这些类型,应省略类型标注。
1794
1795**TypeScript**
1796
1797```typescript
1798try {
1799  // ...
1800} catch (a: unknown) {
1801  // 处理异常
1802}
1803```
1804
1805**ArkTS**
1806
1807```typescript
1808try {
1809  // ...
1810} catch (a) {
1811  // 处理异常
1812}
1813```
1814
1815**相关约束**
1816
1817限制throw语句中表达式的类型
1818
1819### 不支持`for .. in`
1820
1821**规则:**`arkts-no-for-in`
1822
1823**级别:错误**
1824
1825由于在ArkTS中,对象布局在编译时是确定的、并且不能在运行时被改变,所以不支持使用`for .. in`迭代一个对象的属性。对于数组来说,可以使用常规的`for`循环。
1826
1827**TypeScript**
1828
1829```typescript
1830let a: string[] = ['1.0', '2.0', '3.0'];
1831for (let i in a) {
1832  console.log(a[i]);
1833}
1834```
1835
1836**ArkTS**
1837
1838```typescript
1839let a: string[] = ['1.0', '2.0', '3.0'];
1840for (let i = 0; i < a.length; ++i) {
1841  console.log(a[i]);
1842}
1843```
1844
1845### 不支持映射类型
1846
1847**规则:**`arkts-no-mapped-types`
1848
1849**级别:错误**
1850
1851ArkTS不支持映射类型,使用其他语法来表示相同的语义。
1852
1853**TypeScript**
1854
1855```typescript
1856type OptionsFlags<Type> = {
1857  [Property in keyof Type]: boolean
1858}
1859```
1860
1861**ArkTS**
1862
1863```typescript
1864class C {
1865  n: number = 0
1866  s: string = ''
1867}
1868
1869class CFlags {
1870  n: boolean = false
1871  s: boolean = false
1872}
1873```
1874
1875### 不支持`with`语句
1876
1877**规则:**`arkts-no-with`
1878
1879**级别:错误**
1880
1881ArkTS不支持`with`语句,使用其他语法来表示相同的语义。
1882
1883**TypeScript**
1884
1885```typescript
1886with (Math) { // 编译时错误, 但是仍能生成JavaScript代码
1887  let r: number = 42;
1888  let area: number = PI * r * r;
1889}
1890```
1891
1892**ArkTS**
1893
1894```typescript
1895let r: number = 42;
1896let area: number = Math.PI * r * r;
1897```
1898
1899### 限制`throw`语句中表达式的类型
1900
1901**规则:**`arkts-limited-throw`
1902
1903**级别:错误**
1904
1905ArkTS只支持抛出`Error`类或其派生类的实例。禁止抛出其他类型(例如`number`或`string`)的数据。
1906
1907**TypeScript**
1908
1909```typescript
1910throw 4;
1911throw '';
1912throw new Error();
1913```
1914
1915**ArkTS**
1916
1917```typescript
1918throw new Error();
1919```
1920
1921### 限制省略函数返回类型标注
1922
1923**规则:**`arkts-no-implicit-return-types`
1924
1925**级别:错误**
1926
1927ArkTS在部分场景中支持对函数返回类型进行推断。当`return`语句中的表达式是对某个函数或方法进行调用,且该函数或方法的返回类型没有被显著标注时,会出现编译时错误。在这种情况下,请标注函数返回类型。
1928
1929**TypeScript**
1930
1931```typescript
1932// 只有在开启noImplicitAny选项时会产生编译时错误
1933function f(x: number) {
1934  if (x <= 0) {
1935    return x;
1936  }
1937  return g(x);
1938}
1939
1940// 只有在开启noImplicitAny选项时会产生编译时错误
1941function g(x: number) {
1942  return f(x - 1);
1943}
1944
1945function doOperation(x: number, y: number) {
1946  return x + y;
1947}
1948
1949f(10);
1950doOperation(2, 3);
1951```
1952
1953**ArkTS**
1954
1955```typescript
1956// 需标注返回类型:
1957function f(x: number): number {
1958  if (x <= 0) {
1959    return x;
1960  }
1961  return g(x);
1962}
1963
1964// 可以省略返回类型,返回类型可以从f的类型标注推导得到
1965function g(x: number): number {
1966  return f(x - 1);
1967}
1968
1969// 可以省略返回类型
1970function doOperation(x: number, y: number) {
1971  return x + y;
1972}
1973
1974f(10);
1975doOperation(2, 3);
1976```
1977
1978### 不支持参数解构的函数声明
1979
1980**规则:**`arkts-no-destruct-params`
1981
1982**级别:错误**
1983
1984ArkTS要求实参必须直接传递给函数,且必须指定到形参。
1985
1986**TypeScript**
1987
1988```typescript
1989function drawText({ text = '', location: [x, y] = [0, 0], bold = false }) {
1990  text;
1991  x;
1992  y;
1993  bold;
1994}
1995
1996drawText({ text: 'Hello, world!', location: [100, 50], bold: true });
1997```
1998
1999**ArkTS**
2000
2001```typescript
2002function drawText(text: String, location: number[], bold: boolean) {
2003  let x = location[0];
2004  let y = location[1];
2005  text;
2006  x;
2007  y;
2008  bold;
2009}
2010
2011function main() {
2012  drawText('Hello, world!', [100, 50], true);
2013}
2014```
2015
2016### 不支持在函数内声明函数
2017
2018**规则:**`arkts-no-nested-funcs`
2019
2020**级别:错误**
2021
2022ArkTS不支持在函数内声明函数,改用lambda函数。
2023
2024**TypeScript**
2025
2026```typescript
2027function addNum(a: number, b: number): void {
2028
2029  // 函数内声明函数
2030  function logToConsole(message: string): void {
2031    console.log(message);
2032  }
2033
2034  let result = a + b;
2035
2036  // 调用函数
2037  logToConsole('result is ' + result);
2038}
2039```
2040
2041**ArkTS**
2042
2043```typescript
2044function addNum(a: number, b: number): void {
2045  // 使用lambda函数代替声明函数
2046  let logToConsole: (message: string) => void = (message: string): void => {
2047    console.log(message);
2048  }
2049
2050  let result = a + b;
2051
2052  logToConsole('result is ' + result);
2053}
2054```
2055
2056### 不支持在函数和类的静态方法中使用`this`
2057
2058**规则:**`arkts-no-standalone-this`
2059
2060**级别:错误**
2061
2062ArkTS不支持在函数和类的静态方法中使用`this`,只能在类的实例方法中使用`this`。
2063
2064**TypeScript**
2065
2066```typescript
2067function foo(i: string) {
2068  this.count = i; // 只有在开启noImplicitThis选项时会产生编译时错误
2069}
2070
2071class A {
2072  count: string = 'a'
2073  m = foo
2074}
2075
2076let a = new A();
2077console.log(a.count); // 打印a
2078a.m('b');
2079console.log(a.count); // 打印b
2080```
2081
2082**ArkTS**
2083
2084```typescript
2085class A {
2086  count: string = 'a'
2087  m(i: string): void {
2088    this.count = i;
2089  }
2090}
2091
2092function main(): void {
2093  let a = new A();
2094  console.log(a.count);  // 打印a
2095  a.m('b');
2096  console.log(a.count);  // 打印b
2097}
2098```
2099
2100**相关约束**
2101
2102不支持Function.applyFunction.bind以及Function.call
2103
2104### 不支持生成器函数
2105
2106**规则:**`arkts-no-generators`
2107
2108**级别:错误**
2109
2110目前ArkTS不支持生成器函数,使用`async`或`await`机制进行并行任务处理。
2111
2112**TypeScript**
2113
2114```typescript
2115function* counter(start: number, end: number) {
2116  for (let i = start; i <= end; i++) {
2117    yield i;
2118  }
2119}
2120
2121for (let num of counter(1, 5)) {
2122  console.log(num);
2123}
2124```
2125
2126**ArkTS**
2127
2128```typescript
2129async function complexNumberProcessing(str: string): Promise<string> {
2130  // ...
2131  return str;
2132}
2133
2134async function foo() {
2135  for (let i = 1; i <= 5; i++) {
2136    console.log(await complexNumberProcessing(i));
2137  }
2138}
2139
2140foo()
2141```
2142
2143### 使用`instanceof`和`as`进行类型保护
2144
2145**规则:**`arkts-no-is`
2146
2147**级别:错误**
2148
2149ArkTS不支持`is`运算符,必须用`instanceof`运算符替代。在使用之前,必须使用`as`运算符将对象转换为需要的类型。
2150
2151**TypeScript**
2152
2153```typescript
2154class Foo {
2155  foo: string = ''
2156  common: string = ''
2157}
2158
2159class Bar {
2160  bar: string = ''
2161  common: string = ''
2162}
2163
2164function isFoo(arg: any): arg is Foo {
2165  return arg.foo !== undefined;
2166}
2167
2168function doStuff(arg: Foo | Bar) {
2169  if (isFoo(arg)) {
2170    console.log(arg.foo);  // OK
2171    console.log(arg.bar);  // 编译时错误
2172  } else {
2173    console.log(arg.foo);  // 编译时错误
2174    console.log(arg.bar);  // OK
2175  }
2176}
2177
2178doStuff({ foo: 123, common: '123' });
2179doStuff({ bar: 123, common: '123' });
2180```
2181
2182**ArkTS**
2183
2184```typescript
2185class Foo {
2186  foo: string = ''
2187  common: string = ''
2188}
2189
2190class Bar {
2191  bar: string = ''
2192  common: string = ''
2193}
2194
2195function isFoo(arg: Object): boolean {
2196  return arg instanceof Foo;
2197}
2198
2199function doStuff(arg: Object): void {
2200  if (isFoo(arg)) {
2201    let fooArg = arg as Foo;
2202    console.log(fooArg.foo);   // OK
2203    console.log(arg.bar);    // 编译时错误
2204  } else {
2205    let barArg = arg as Bar;
2206    console.log(arg.foo);    // 编译时错误
2207    console.log(barArg.bar);   // OK
2208  }
2209}
2210
2211function main(): void {
2212  doStuff(new Foo());
2213  doStuff(new Bar());
2214}
2215```
2216
2217### 部分支持展开运算符
2218
2219**规则:**`arkts-no-spread`
2220
2221**级别:错误**
2222
2223ArkTS仅支持使用展开运算符展开数组、`Array`的子类和`TypedArray`(例如`Int32Array`)。仅支持使用在以下场景中:
22241. 传递给剩余参数时
22252. 复制一个数组到数组字面量
2226
2227**TypeScript**
2228
2229```typescript
2230function foo(x: number, y: number, z: number) {
2231  // ...
2232}
2233
2234let args: [number, number, number] = [0, 1, 2];
2235foo(...args);
2236```
2237
2238**ArkTS**
2239
2240```typescript
2241function log_numbers(x: number, y: number, z: number) {
2242  // ...
2243}
2244
2245let numbers: number[] = [1, 2, 3];
2246log_numbers(numbers[0], numbers[1], numbers[2]);
2247```
2248
2249**TypeScript**
2250
2251```typescript
2252let point2d = { x: 1, y: 2 };
2253let point3d = { ...point2d, z: 3 };
2254```
2255
2256**ArkTS**
2257
2258```typescript
2259class Point2D {
2260  x: number = 0; y: number = 0
2261}
2262
2263class Point3D {
2264  x: number = 0; y: number = 0; z: number = 0
2265  constructor(p2d: Point2D, z: number) {
2266    this.x = p2d.x;
2267    this.y = p2d.y;
2268    this.z = z;
2269  }
2270}
2271
2272let p3d = new Point3D({ x: 1, y: 2 } as Point2D, 3);
2273
2274class DerivedFromArray extends Uint16Array {};
2275
2276let arr1 = [1, 2, 3];
2277let arr2 = new Uint16Array([4, 5, 6]);
2278let arr3 = new DerivedFromArray([7, 8, 9]);
2279let arr4 = [...arr1, 10, ...arr2, 11, ...arr3];
2280```
2281
2282### 接口不能继承具有相同方法的两个接口
2283
2284**规则:**`arkts-no-extend-same-prop`
2285
2286**级别:错误**
2287
2288在TypeScript中,如果一个接口继承了具有相同方法的两个接口,则该接口必须使用联合类型来声明该方法的返回值类型。在ArkTS中,由于一个接口中不能包含两个无法区分的方法(例如两个参数列表相同但返回类型不同的方法),因此,接口不能继承具有相同方法的两个接口。
2289
2290**TypeScript**
2291
2292```typescript
2293interface Mover {
2294  getStatus(): { speed: number }
2295}
2296interface Shaker {
2297  getStatus(): { frequency: number }
2298}
2299
2300interface MoverShaker extends Mover, Shaker {
2301  getStatus(): {
2302    speed: number
2303    frequency: number
2304  }
2305}
2306
2307class C implements MoverShaker {
2308  private speed: number = 0
2309  private frequency: number = 0
2310
2311  getStatus() {
2312    return { speed: this.speed, frequency: this.frequency };
2313  }
2314}
2315```
2316
2317**ArkTS**
2318
2319```typescript
2320class MoveStatus {
2321  public speed: number
2322  constructor() {
2323    this.speed = 0;
2324  }
2325}
2326interface Mover {
2327  getMoveStatus(): MoveStatus
2328}
2329
2330class ShakeStatus {
2331  public frequency: number
2332  constructor() {
2333    this.frequency = 0;
2334  }
2335}
2336interface Shaker {
2337  getShakeStatus(): ShakeStatus
2338}
2339
2340class MoveAndShakeStatus {
2341  public speed: number
2342  public frequency: number
2343  constructor() {
2344    this.speed = 0;
2345    this.frequency = 0;
2346  }
2347}
2348
2349class C implements Mover, Shaker {
2350  private move_status: MoveStatus
2351  private shake_status: ShakeStatus
2352
2353  constructor() {
2354    this.move_status = new MoveStatus();
2355    this.shake_status = new ShakeStatus();
2356  }
2357
2358  public getMoveStatus(): MoveStatus {
2359    return this.move_status;
2360  }
2361
2362  public getShakeStatus(): ShakeStatus {
2363    return this.shake_status;
2364  }
2365
2366  public getStatus(): MoveAndShakeStatus {
2367    return {
2368      speed: this.move_status.speed,
2369      frequency: this.shake_status.frequency
2370    };
2371  }
2372}
2373```
2374
2375### 不支持声明合并
2376
2377**规则:**`arkts-no-decl-merging`
2378
2379**级别:错误**
2380
2381ArkTS不支持类、接口的声明合并。
2382
2383**TypeScript**
2384
2385```typescript
2386interface Document {
2387  createElement(tagName: any): Element
2388}
2389
2390interface Document {
2391  createElement(tagName: string): HTMLElement
2392}
2393
2394interface Document {
2395  createElement(tagName: number): HTMLDivElement
2396  createElement(tagName: boolean): HTMLSpanElement
2397  createElement(tagName: string, value: number): HTMLCanvasElement
2398}
2399```
2400
2401**ArkTS**
2402
2403```typescript
2404interface Document {
2405  createElement(tagName: number): HTMLDivElement
2406  createElement(tagName: boolean): HTMLSpanElement
2407  createElement(tagName: string, value: number): HTMLCanvasElement
2408  createElement(tagName: string): HTMLElement
2409  createElement(tagName: Object): Element
2410}
2411```
2412
2413### 接口不能继承类
2414
2415**规则:**`arkts-extends-only-class`
2416
2417**级别:错误**
2418
2419ArkTS不支持接口继承类,接口只能继承接口。
2420
2421**TypeScript**
2422
2423```typescript
2424class Control {
2425  state: number = 0
2426}
2427
2428interface SelectableControl extends Control {
2429  select(): void
2430}
2431```
2432
2433**ArkTS**
2434
2435```typescript
2436interface Control {
2437  state: number
2438}
2439
2440interface SelectableControl extends Control {
2441  select(): void
2442}
2443```
2444
2445### 不支持构造函数类型
2446
2447**规则:**`arkts-no-ctor-signatures-funcs`
2448
2449**级别:错误**
2450
2451ArkTS不支持使用构造函数类型,改用lambda函数。
2452
2453**TypeScript**
2454
2455```typescript
2456class Person {
2457  constructor(
2458    name: string,
2459    age: number
2460  ) {}
2461}
2462type PersonCtor = new (name: string, age: number) => Person
2463
2464function createPerson(Ctor: PersonCtor, name: string, age: number): Person
2465{
2466  return new Ctor(name, age);
2467}
2468
2469const person = createPerson(Person, 'John', 30);
2470```
2471
2472**ArkTS**
2473
2474```typescript
2475class Person {
2476  constructor(
2477    name: string,
2478    age: number
2479  ) {}
2480}
2481type PersonCtor = (n: string, a: number) => Person
2482
2483function createPerson(Ctor: PersonCtor, n: string, a: number): Person {
2484  return Ctor(n, a);
2485}
2486
2487let Impersonizer: PersonCtor = (n: string, a: number): Person => {
2488  return new Person(n, a);
2489}
2490
2491const person = createPerson(Impersonizer, 'John', 30);
2492```
2493
2494### 只能使用类型相同的编译时表达式初始化枚举成员
2495
2496**规则:**`arkts-no-enum-mixed-types`
2497
2498**级别:错误**
2499
2500ArkTS不支持使用在运行期间才能计算的表达式来初始化枚举成员。此外,枚举中所有显式初始化的成员必须具有相同的类型。
2501
2502**TypeScript**
2503
2504```typescript
2505enum E1 {
2506  A = 0xa,
2507  B = 0xb,
2508  C = Math.random(),
2509  D = 0xd,
2510  E // 推断出0xe
2511}
2512
2513enum E2 {
2514  A = 0xa,
2515  B = '0xb',
2516  C = 0xc,
2517  D = '0xd'
2518}
2519```
2520
2521**ArkTS**
2522
2523```typescript
2524enum E1 {
2525  A = 0xa,
2526  B = 0xb,
2527  C = 0xc,
2528  D = 0xd,
2529  E // 推断出0xe
2530}
2531
2532enum E2 {
2533  A = '0xa',
2534  B = '0xb',
2535  C = '0xc',
2536  D = '0xd'
2537}
2538```
2539
2540### 不支持`enum`声明合并
2541
2542**规则:**`arkts-no-enum-merging`
2543
2544**级别:错误**
2545
2546ArkTS不支持`enum`声明合并。
2547
2548**TypeScript**
2549
2550```typescript
2551enum ColorSet {
2552  RED,
2553  GREEN
2554}
2555enum ColorSet {
2556  YELLOW = 2
2557}
2558enum ColorSet {
2559  BLACK = 3,
2560  BLUE
2561}
2562```
2563
2564**ArkTS**
2565
2566```typescript
2567enum ColorSet {
2568  RED,
2569  GREEN,
2570  YELLOW,
2571  BLACK,
2572  BLUE
2573}
2574```
2575
2576### 命名空间不能被用作对象
2577
2578**规则:**`arkts-no-ns-as-obj`
2579
2580**级别:错误**
2581
2582ArkTS不支持将命名空间用作对象,可以使用类或模块。
2583
2584**TypeScript**
2585
2586```typescript
2587namespace MyNamespace {
2588  export let x: number
2589}
2590
2591let m = MyNamespace;
2592m.x = 2;
2593```
2594
2595**ArkTS**
2596
2597```typescript
2598namespace MyNamespace {
2599  export let x: number
2600}
2601
2602MyNamespace.x = 2;
2603```
2604
2605### 不支持命名空间中的非声明语句
2606
2607**规则:**`arkts-no-ns-statements`
2608
2609**级别:错误**
2610
2611在ArkTS中,命名空间用于定义标志符可见范围,只在编译时有效。因此,不支持命名空间中的非声明语句。可以将非声明语句写在函数中。
2612
2613**TypeScript**
2614
2615```typescript
2616namespace A {
2617  export let x: number
2618  x = 1;
2619}
2620```
2621
2622**ArkTS**
2623
2624```typescript
2625namespace A {
2626  export let x: number
2627
2628  export function init() {
2629    x = 1;
2630  }
2631}
2632
2633// 调用初始化函数来执行
2634A.init();
2635```
2636
2637### 不支持`import default as ...`
2638
2639**规则:**`arkts-no-import-default-as`
2640
2641**级别:错误**
2642
2643ArkTS不支持`import default as ...`语法,使用显式的`import ... from ...`语法。
2644
2645**TypeScript**
2646
2647```typescript
2648import { default as d } from 'mod'
2649```
2650
2651**ArkTS**
2652
2653```typescript
2654import d from 'mod'
2655```
2656
2657### 不支持`require`和`import`赋值表达式
2658
2659**规则:**`arkts-no-require`
2660
2661**级别:错误**
2662
2663ArkTS不支持通过`require`导入,也不支持`import`赋值表达式,改用`import`。
2664
2665**TypeScript**
2666
2667```typescript
2668import m = require('mod')
2669```
2670
2671**ArkTS**
2672
2673```typescript
2674import * as m from 'mod'
2675```
2676
2677**相关约束**
2678
2679不支持export = ...语法
2680
2681### 不支持`export = ...`语法
2682
2683**规则:**`arkts-no-export-assignment`
2684
2685**级别:错误**
2686
2687ArkTS不支持`export = ...`语法,改用常规的`export`或`import`。
2688
2689**TypeScript**
2690
2691```typescript
2692// module1
2693export = Point
2694
2695class Point {
2696  constructor(x: number, y: number) {}
2697  static origin = new Point(0, 0)
2698}
2699
2700// module2
2701import Pt = require('module1')
2702
2703let p = Pt.Point.origin;
2704```
2705
2706**ArkTS**
2707
2708```typescript
2709// module1
2710export class Point {
2711  constructor(x: number, y: number) {}
2712  static origin = new Point(0, 0)
2713}
2714
2715// module2
2716import * as Pt from 'module1'
2717
2718let p = Pt.Point.origin
2719```
2720
2721**相关约束**
2722
2723不支持require和import赋值表达式
2724
2725### 不支持ambient module声明
2726
2727**规则:**`arkts-no-ambient-decls`
2728
2729**级别:错误**
2730
2731由于ArkTS本身有与JavaScript交互的机制,ArkTS不支持ambient module声明。
2732
2733**TypeScript**
2734
2735```typescript
2736declare module 'someModule' {
2737  export function normalize(s: string): string;
2738}
2739```
2740
2741**ArkTS**
2742
2743```typescript
2744// 从原始模块中导入需要的内容
2745import { normalize } from 'someModule'
2746```
2747
2748**相关约束**
2749
2750不支持在模块名中使用通配符
2751
2752### 不支持在模块名中使用通配符
2753
2754**规则:**`arkts-no-module-wildcards`
2755
2756**级别:错误**
2757
2758由于在ArkTS中,导入是编译时而非运行时行为,因此,不支持在模块名中使用通配符。
2759
2760**TypeScript**
2761
2762```typescript
2763// 声明
2764declare module '*!text' {
2765  const content: string
2766  export default content
2767}
2768
2769// 使用代码
2770import fileContent from 'some.txt!text'
2771```
2772
2773**ArkTS**
2774
2775```typescript
2776// 声明
2777declare namespace N {
2778  function foo(x: number): number
2779}
2780
2781// 使用代码
2782import * as m from 'module'
2783console.log('N.foo called: ' + N.foo(42));
2784```
2785
2786**相关约束**
2787
2788* 不支持ambient module声明
2789* 不支持通用模块定义(UMD)
2790
2791### 不支持通用模块定义(UMD)
2792
2793**规则:**`arkts-no-umd`
2794
2795**级别:错误**
2796
2797ArkTS不支持通用模块定义(UMD)。因为在ArkTS中没有“脚本”的概念(相对于“模块”)。此外,在ArkTS中,导入是编译时而非运行时特性。改用`export`和`import`语法。
2798
2799**TypeScript**
2800
2801```typescript
2802// math-lib.d.ts
2803export const isPrime(x: number): boolean
2804export as namespace mathLib
2805
2806// 脚本中
2807mathLib.isPrime(2)
2808```
2809
2810**ArkTS**
2811
2812```typescript
2813// math-lib.d.ts
2814namespace mathLib {
2815  export isPrime(x: number): boolean
2816}
2817
2818// 程序中
2819import { mathLib } from 'math-lib'
2820mathLib.isPrime(2)
2821```
2822
2823**相关约束**
2824
2825不支持在模块名中使用通配符
2826
2827### 不支持`new.target`
2828
2829**规则:**`arkts-no-new-target`
2830
2831**级别:错误**
2832
2833ArkTS没有原型的概念,因此不支持`new.target`。此特性不符合静态类型的原则。
2834
2835**相关约束**
2836
2837不支持在原型上赋值
2838
2839### 不支持确定赋值断言
2840
2841**规则:**`arkts-no-definite-assignment`
2842
2843**级别:警告**
2844
2845ArkTS不支持确定赋值断言,例如:`let v!: T`。改为在声明变量的同时为变量赋值。
2846
2847**TypeScript**
2848
2849```typescript
2850let x!: number // 提示:在使用前将x初始化
2851
2852initialize();
2853
2854function initialize() {
2855  x = 10;
2856}
2857
2858console.log('x = ' + x);
2859```
2860
2861**ArkTS**
2862
2863```typescript
2864function initialize(): number {
2865  return 10;
2866}
2867
2868let x: number = initialize();
2869
2870console.log('x = ' + x);
2871```
2872
2873### 不支持在原型上赋值
2874
2875**规则:**`arkts-no-prototype-assignment`
2876
2877**级别:错误**
2878
2879ArkTS没有原型的概念,因此不支持在原型上赋值。此特性不符合静态类型的原则。
2880
2881**TypeScript**
2882
2883```typescript
2884let C = function(p) {
2885  this.p = p; // 只有在开启noImplicitThis选项时会产生编译时错误
2886}
2887
2888C.prototype = {
2889  m() {
2890    console.log(this.p);
2891  }
2892}
2893
2894C.prototype.q = function(r: string) {
2895  return this.p == r;
2896}
2897```
2898
2899**ArkTS**
2900
2901```typescript
2902class C {
2903  p: string = ''
2904  m() {
2905    console.log(this.p);
2906  }
2907  q(r: string) {
2908    return this.p == r;
2909  }
2910}
2911```
2912
2913**相关约束**
2914
2915不支持new.target
2916
2917### 不支持`globalThis`
2918
2919**规则:**`arkts-no-globalthis`
2920
2921**级别:警告**
2922
2923由于ArkTS不支持动态更改对象的布局,因此不支持全局作用域和`globalThis`。
2924
2925**TypeScript**
2926
2927```typescript
2928// 全局文件中
2929var abc = 100;
2930
2931// 从上面引用'abc'
2932let x = globalThis.abc;
2933```
2934
2935**ArkTS**
2936
2937```typescript
2938// file1
2939export let abc: number = 100;
2940
2941// file2
2942import * as M from 'file1'
2943
2944let x = M.abc;
2945```
2946
2947**相关约束**
2948
2949* 不支持声明函数的属性
2950* 标准库使用限制
2951
2952### 不支持一些utility类型
2953
2954**规则:**`arkts-no-utility-types`
2955
2956**级别:错误**
2957
2958ArkTS仅支持`Partial`、`Required`、`Readonly`和`Record`,不支持TypeScript中其他的`Utility Types`。
2959
2960对于`Record`类型的对象,通过索引访问到的值的类型是包含`undefined`的联合类型。
2961
2962### 不支持对函数声明属性
2963
2964**规则:**`arkts-no-func-props`
2965
2966**级别:错误**
2967
2968由于ArkTS不支持动态改变函数对象布局,因此,不支持对函数声明属性。
2969
2970**相关约束**
2971
2972不支持globalThis
2973
2974### 不支持`Function.apply`和`Function.call`
2975
2976**规则:**`arkts-no-func-apply-call`
2977
2978**级别:错误**
2979
2980ArkTS不允许使用标准库函数`Function.apply`和`Function.call`。标准库使用这些函数来显式设置被调用函数的`this`参数。在ArkTS中,`this`的语义仅限于传统的OOP风格,函数体中禁止使用`this`。
2981
2982**相关约束**
2983
2984不支持在函数中使用this
2985
2986### 不支持`Function.bind`
2987
2988**规则:**`arkts-no-func-bind`
2989
2990**级别:警告**
2991
2992ArkTS不允许使用标准库函数`Function.bind`。标准库使用这些函数来显式设置被调用函数的`this`参数。在ArkTS中,`this`的语义仅限于传统的OOP风格,函数体中禁止使用`this`。
2993
2994**相关约束**
2995
2996不支持在函数中使用this
2997
2998### 不支持`as const`断言
2999
3000**规则:**`arkts-no-as-const`
3001
3002**级别:错误**
3003
3004ArkTS不支持`as const`断言。在标准TypeScript中,`as const`用于标注字面量的相应字面量类型,而ArkTS不支持字面量类型。
3005
3006**TypeScript**
3007
3008```typescript
3009// 'hello'类型
3010let x = 'hello' as const;
3011
3012// 'readonly [10, 20]'类型
3013let y = [10, 20] as const;
3014
3015// '{ readonly text: 'hello' }'类型
3016let z = { text: 'hello' } as const;
3017```
3018
3019**ArkTS**
3020
3021```typescript
3022// 'string'类型
3023let x: string = 'hello';
3024
3025// 'number[]'类型
3026let y: number[] = [10, 20];
3027
3028class Label {
3029  text: string = ''
3030}
3031
3032// 'Label'类型
3033let z: Label = {
3034  text: 'hello'
3035}
3036```
3037
3038### 不支持导入断言
3039
3040**规则:**`arkts-no-import-assertions`
3041
3042**级别:错误**
3043
3044由于在ArkTS中,导入是编译时而非运行时特性,因此,ArkTS不支持导入断言。在运行时检查导入的API是否正确,对于静态类型的语言来说是没有意义的。改用常规的`import`语法。
3045
3046**TypeScript**
3047
3048```typescript
3049import { obj } from 'something.json' assert { type: 'json' }
3050```
3051
3052**ArkTS**
3053
3054```typescript
3055// 编译时将检查导入T的正确性
3056import { something } from 'module'
3057```
3058
3059**相关约束**
3060
3061* 不支持在模块名中使用通配符
3062* 不支持通用模块定义(UMD)
3063* 不支持运行时导入断言
3064
3065### 限制使用标准库
3066
3067**规则:**`arkts-limited-stdlib`
3068
3069**级别:错误**
3070
3071ArkTS不允许使用TypeScript或JavaScript标准库中的某些接口。大部分接口与动态特性有关。ArkTS中禁止使用以下接口:
3072
3073全局对象的属性和方法:`eval`
3074
3075`Object`:`__proto__`、`__defineGetter__`、`__defineSetter__`、
3076`__lookupGetter__`、`__lookupSetter__`、`assign`、`create`、
3077`defineProperties`、`defineProperty`、`freeze`、
3078`fromEntries`、`getOwnPropertyDescriptor`、`getOwnPropertyDescriptors`、
3079`getOwnPropertySymbols`、`getPrototypeOf`、
3080`hasOwnProperty`、`is`、`isExtensible`、`isFrozen`、
3081`isPrototypeOf`、`isSealed`、`preventExtensions`、
3082`propertyIsEnumerable`、`seal`、`setPrototypeOf`
3083
3084`Reflect`:`apply`、`construct`、`defineProperty`、`deleteProperty`、
3085`getOwnPropertyDescriptor`、`getPrototypeOf`、
3086`isExtensible`、`preventExtensions`、
3087`setPrototypeOf`
3088
3089`Proxy`:`handler.apply()`、`handler.construct()`、
3090`handler.defineProperty()`、`handler.deleteProperty()`、`handler.get()`、
3091`handler.getOwnPropertyDescriptor()`、`handler.getPrototypeOf()`、
3092`handler.has()`、`handler.isExtensible()`、`handler.ownKeys()`、
3093`handler.preventExtensions()`、`handler.set()`、`handler.setPrototypeOf()`
3094
3095**相关约束**
3096
3097* 对象的属性名必须是合法的标识符
3098* 不支持Symbol() API
3099* 不支持通过索引访问字段
3100* 仅允许在表达式中使用typeof运算符
3101* 不支持in运算符
3102* 不支持globalThis
3103
3104### 强制进行严格类型检查
3105
3106**规则:**`arkts-strict-typing`
3107
3108**级别:错误**
3109
3110在编译阶段,会进行TypeScript严格模式的类型检查,包括:
3111`noImplicitReturns`,
3112`strictFunctionTypes`,
3113`strictNullChecks`,
3114`strictPropertyInitialization`。
3115
3116**TypeScript**
3117
3118```typescript
3119// 只有在开启noImplicitReturns选项时会产生编译时错误
3120function foo(s: string): string {
3121  if (s != '') {
3122    console.log(s);
3123    return s;
3124  } else {
3125    console.log(s);
3126  }
3127}
3128
3129let n: number = null; // 只有在开启strictNullChecks选项时会产生编译时错误
3130```
3131
3132**ArkTS**
3133
3134```typescript
3135function foo(s: string): string {
3136  console.log(s);
3137  return s;
3138}
3139
3140let n1: number | null = null;
3141let n2: number = 0;
3142```
3143
3144在定义类时,如果无法在声明时或者构造函数中初始化某实例属性,那么可以使用确定赋值断言符`!`来消除`strictPropertyInitialization`的报错。
3145
3146使用确定赋值断言符会增加代码错误的风险,开发者需要保证该实例属性在被使用前已被赋值,否则可能会产生运行时异常。
3147
3148使用确定赋值断言符会增加运行时的类型检查,从而增加额外的运行时开销,所以应尽可能避免使用确定赋值断言符。
3149
3150使用确定赋值断言符将产生`warning: arkts-no-definite-assignment`。
3151
3152**TypeScript**
3153
3154```typescript
3155class C {
3156  name: string  // 只有在开启strictPropertyInitialization选项时会产生编译时错误
3157  age: number   // 只有在开启strictPropertyInitialization选项时会产生编译时错误
3158}
3159
3160let c = new C();
3161```
3162
3163**ArkTS**
3164
3165```typescript
3166class C {
3167  name: string = ''
3168  age!: number      // warning: arkts-no-definite-assignment
3169
3170  initAge(age: number) {
3171    this.age = age;
3172  }
3173}
3174
3175let c = new C();
3176c.initAge(10);
3177```
3178
3179**相关约束**
3180
3181* 使用具体的类型而非any或unknown
3182* 不允许通过注释关闭类型检查
3183
3184### 不允许通过注释关闭类型检查
3185
3186**规则:**`arkts-strict-typing-required`
3187
3188**级别:错误**
3189
3190在ArkTS中,类型检查不是可选项。不允许通过注释关闭类型检查,不支持使用`@ts-ignore`和`@ts-nocheck`。
3191
3192**TypeScript**
3193
3194```typescript
3195// @ts-nocheck
3196// ...
3197// 关闭了类型检查后的代码
3198// ...
3199
3200let s1: string = null; // 没有报错
3201
3202// @ts-ignore
3203let s2: string = null; // 没有报错
3204```
3205
3206**ArkTS**
3207
3208```typescript
3209let s1: string | null = null; // 没有报错,合适的类型
3210let s2: string = null; // 编译时报错
3211```
3212
3213**相关约束**
3214
3215* 使用具体的类型而非any或unknown
3216* 强制进行严格类型检查
3217
3218### 允许.ets文件`import`.ets/.ts/.js文件源码, 不允许.ts/.js文件`import`.ets文件源码
3219
3220**规则:**`arkts-no-ts-deps`
3221
3222**级别:错误**
3223
3224.ets文件可以`import`.ets/.ts/.js文件源码,但是.ts/.js文件不允许`import`.ets文件源码。
3225
3226**TypeScript**
3227
3228```typescript
3229// app.ets
3230export class C {
3231  // ...
3232}
3233
3234// lib.ts
3235import { C } from 'app'
3236```
3237
3238**ArkTS**
3239
3240```typescript
3241// lib1.ets
3242export class C {
3243  // ...
3244}
3245
3246// lib2.ets
3247import { C } from 'lib1'
3248```
3249
3250### `class`不能被用作对象
3251
3252**规则:**`arkts-no-classes-as-obj`
3253
3254**级别:警告**
3255
3256在ArkTS中,`class`声明的是一个新的类型,不是一个值。因此,不支持将`class`用作对象(例如将`class`赋值给一个对象)。
3257
3258### 不支持在`import`语句前使用其他语句
3259
3260**规则:**`arkts-no-misplaced-imports`
3261
3262**级别:错误**
3263
3264在ArkTS中,除动态`import`语句外,所有`import`语句需要放在所有其他语句之前。
3265
3266**TypeScript**
3267
3268```typescript
3269class C {
3270  s: string = ''
3271  n: number = 0
3272}
3273
3274import foo from 'module1'
3275```
3276
3277**ArkTS**
3278
3279```typescript
3280import foo from 'module1'
3281
3282class C {
3283  s: string = ''
3284  n: number = 0
3285}
3286
3287import('module2').then(() => {}).catch(() => {})  // 动态import
3288```
3289
3290### 限制使用`ESObject`类型
3291
3292**规则:**`arkts-limited-esobj`
3293
3294**级别:警告**
3295
3296为了防止动态对象(来自.ts/.js文件)在静态代码(.ets文件)中的滥用,`ESObject`类型在ArkTS中的使用是受限的。唯一允许使用`ESObject`类型的场景是将其用在局部变量的声明中。`ESObject`类型变量的赋值也是受限的,只能被来自跨语言调用的对象赋值,例如:`ESObject`、`any`、`unknown`、匿名类型等类型的变量。禁止使用静态类型的值(在.ets文件中定义的)初始化`ESObject`类型变量。`ESObject`类型变量只能用在跨语言调用的函数里或者赋值给另一个`ESObject`类型变量。
3297
3298**ArkTS**
3299
3300```typescript
3301// lib.d.ts
3302declare function foo(): any;
3303declare function bar(a: any): number;
3304
3305// main.ets
3306let e0: ESObject = foo(); // 编译时错误:ESObject类型只能用于局部变量
3307
3308function f() {
3309  let e1 = foo();        // 编译时错误:e1的类型是any
3310  let e2: ESObject = 1;  // 编译时错误:不能用非动态值初始化ESObject类型变量
3311  let e3: ESObject = {}; // 编译时错误:不能用非动态值初始化ESObject类型变量
3312  let e4: ESObject = []; // 编译时错误:不能用非动态值初始化ESObject类型变量
3313  let e5: ESObject = ''; // 编译时错误:不能用非动态值初始化ESObject类型变量
3314  e5['prop'];            // 编译时错误:不能访问ESObject类型变量的属性
3315  e5[1];                 // 编译时错误:不能访问ESObject类型变量的属性
3316  e5.prop;               // 编译时错误:不能访问ESObject类型变量的属性
3317
3318  let e6: ESObject = foo(); // OK,显式标注ESObject类型
3319  let e7 = e6;              // OK,使用ESObject类型赋值
3320  bar(e7);                  // OK,ESObject类型变量传给跨语言调用的函数
3321}
3322
3323**相关约束**
3324
3325* 对象的属性名必须是合法的标识符
3326* 不支持Symbol() API
3327* 不支持通过索引访问字段
3328* 仅允许在表达式中使用typeof运算符
3329* 不支持in运算符
3330* 不支持globalThis
3331