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.apply、Function.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