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