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