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