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