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