1# Adaptation Cases 2 3In this document, various use cases are presented to provide suggestions on adapting TS code to ArkTS for compliance with ArkTS syntax rules. Each chapter is named after an ArkTS syntax rule. Each use case provides the TS code before adaptation and the ArkTS code after adaptation. 4 5## arkts-identifiers-as-prop-names 6 7**Before adaptation** 8 9```typescript 10interface W { 11 bundleName: string 12 action: string 13 entities: string[] 14} 15 16let wantInfo: W = { 17 'bundleName': 'com.huawei.hmos.browser', 18 'action': 'ohos.want.action.viewData', 19 'entities': ['entity.system.browsable'] 20} 21``` 22 23**After adaptation** 24 25```typescript 26interface W { 27 bundleName: string 28 action: string 29 entities: string[] 30} 31 32let wantInfo: W = { 33 bundleName: 'com.huawei.hmos.browser', 34 action: 'ohos.want.action.viewData', 35 entities: ['entity.system.browsable'] 36} 37``` 38 39## arkts-no-any-unknown 40 41### Changing any and unknown to Specific Types 42 43```typescript 44function printObj(obj: any) { 45 console.log(obj); 46} 47 48printObj('abc'); 49``` 50 51**After adaptation** 52 53```typescript 54function printObj(obj: string) { 55 console.log(obj); 56} 57 58printObj('abc'); 59``` 60 61### Marking JSON.parse Return Value Type 62 63**Before adaptation** 64 65```typescript 66class A { 67 v: number = 0 68 s: string = '' 69 70 foo(str: string) { 71 let tmpStr = JSON.parse(str); 72 if (tmpStr.add != undefined) { 73 this.v = tmpStr.v; 74 this.s = tmpStr.s; 75 } 76 } 77} 78``` 79 80**After adaptation** 81 82```typescript 83class A { 84 v: number = 0 85 s: string = '' 86 87 foo(str: string) { 88 let tmpStr: Record<string, Object> = JSON.parse(str); 89 if (tmpStr.add != undefined) { 90 this.v = tmpStr.v as number; 91 this.s = tmpStr.s as string; 92 } 93 } 94} 95``` 96 97### Using Record Type 98 99**Before adaptation** 100 101```typescript 102function printProperties(obj: any) { 103 console.log(obj.name); 104 console.log(obj.value); 105} 106``` 107 108**After adaptation** 109 110```typescript 111function printProperties(obj: Record<string, Object>) { 112 console.log(obj.name as string); 113 console.log(obj.value as string); 114} 115``` 116 117## arkts-no-call-signature 118 119Use the function type instead. 120 121**Before adaptation** 122 123```typescript 124interface I { 125 (value: string): void; 126} 127 128function foo(fn: I) { 129 fn('abc'); 130} 131 132foo((value: string) => { 133 console.log(value); 134}) 135``` 136 137 138**After adaptation** 139 140```typescript 141type I = (value: string) => void 142 143function foo(fn: I) { 144 fn('abc'); 145} 146 147foo((value: string) => { 148 console.log(value); 149}) 150``` 151 152## arkts-no-ctor-signatures-type 153 154**Before adaptation** 155 156```typescript 157class Controller { 158 value: string = '' 159 160 constructor(value: string) { 161 this.value = value; 162 } 163} 164 165type ControllerConstructor = { 166 new (value: string): Controller; 167} 168 169class Menu { 170 controller: ControllerConstructor = Controller 171 createController() { 172 if (this.controller) { 173 return new this.controller(123); 174 } 175 return null; 176 } 177} 178 179let t = new Menu(); 180console.log(t.createController()!.value); 181``` 182 183**After adaptation** 184 185```typescript 186class Controller { 187 value: string = '' 188 189 constructor(value: string) { 190 this.value = value; 191 } 192} 193 194type ControllerConstructor = () => Controller; 195 196class Menu { 197 controller: ControllerConstructor = () => { 198 return new Controller('abc'); 199 } 200 201 createController() { 202 if (this.controller) { 203 return this.controller(); 204 } 205 return null; 206 } 207} 208 209let t: Menu = new Menu(); 210console.log(t.createController()!.value); 211``` 212 213## arkts-no-indexed-signatures 214 215Use the **Record** type instead. 216 217**Before adaptation** 218 219```typescript 220function foo(data: { [key: string]: string }) { 221 data['a'] = 'a'; 222 data['b'] = 'b'; 223 data['c'] = 'c'; 224} 225``` 226 227**After adaptation** 228 229```typescript 230function foo(data: Record<string, string>) { 231 data['a'] = 'a'; 232 data['b'] = 'b'; 233 data['c'] = 'c'; 234} 235``` 236 237## arkts-no-typing-with-this 238 239**Before adaptation** 240 241```typescript 242class C { 243 getInstance(): this { 244 return this; 245 } 246} 247``` 248 249**After adaptation** 250 251```typescript 252class C { 253 getInstance(): C { 254 return this; 255 } 256} 257``` 258 259## arkts-no-ctor-prop-decls 260 261**Before adaptation** 262 263```typescript 264class Person { 265 constructor(readonly name: string) {} 266 267 getName(): string { 268 return this.name; 269 } 270} 271``` 272 273**After adaptation** 274 275```typescript 276class Person { 277 name: string 278 constructor(name: string) { 279 this.name = name; 280 } 281 282 getName(): string { 283 return this.name; 284 } 285} 286``` 287 288## arkts-no-ctor-signatures-iface 289 290**Before adaptation** 291 292```typescript 293class Controller { 294 value: string = '' 295 296 constructor(value: string) { 297 this.value = value; 298 } 299} 300 301interface ControllerConstructor { 302 new (value: string): Controller; 303} 304 305class Menu { 306 controller: ControllerConstructor = Controller 307 createController() { 308 if (this.controller) { 309 return new this.controller('abc'); 310 } 311 return null; 312 } 313} 314 315let t = new Menu(); 316console.log(t.createController()!.value); 317``` 318 319**After adaptation** 320 321```typescript 322class Controller { 323 value: string = '' 324 325 constructor(value: string) { 326 this.value = value; 327 } 328} 329 330type ControllerConstructor = () => Controller; 331 332class Menu { 333 controller: ControllerConstructor = () => { 334 return new Controller('abc'); 335 } 336 337 createController() { 338 if (this.controller) { 339 return this.controller(); 340 } 341 return null; 342 } 343} 344 345let t: Menu = new Menu(); 346console.log(t.createController()!.value); 347``` 348 349## arkts-no-props-by-index 350 351Use the **Record** type to access object attributes. 352 353**Before adaptation** 354 355```typescript 356import myRouter from '@ohos.router'; 357let params: Object = myRouter.getParams(); 358let funNum: number = params['funNum']; 359let target: string = params['target']; 360``` 361 362**After adaptation** 363 364```typescript 365import myRouter from '@ohos.router'; 366let params = myRouter.getParams() as Record<string, string | number>; 367let funNum: number = params.funNum as number; 368let target: string = params.target as string; 369``` 370 371## arkts-no-inferred-generic-params 372 373**Before adaptation** 374 375```typescript 376class A { 377 str: string = '' 378} 379class B extends A {} 380class C extends A {} 381 382let arr: Array<A> = []; 383 384let originMenusMap:Map<string, C> = new Map(arr.map(item => [item.str, (item instanceof C) ? item: null])); 385``` 386 387**After adaptation** 388 389```typescript 390class A { 391 str: string = '' 392} 393class B extends A {} 394class C extends A {} 395 396let arr: Array<A> = []; 397 398let originMenusMap: Map<string, C | null> = new Map<string, C | null>(arr.map<[string, C | null]>(item => [item.str, (item instanceof C) ? item: null])); 399``` 400 401**Reason for change** 402 403**(item instanceof C) ? item: null** needs to be declared as type **C | null**. This is because the compiler cannot deduce the generic type parameter of **map**, and explicit type annotation is required. 404 405## arkts-no-regexp-literals 406 407**Before adaptation** 408 409```typescript 410let regex: RegExp = /\s*/g; 411``` 412 413**After adaptation** 414 415```typescript 416let regexp: RegExp = new RegExp('\\s*','g'); 417``` 418 419**Reason for change** 420 421To include a flag in a regular expression, use it as a parameter of **new RegExp()**. 422 423## arkts-no-untyped-obj-literals 424 425### Specifying Object Literal Type for Type Imports 426 427**Before adaptation** 428 429```typescript 430const area = { 431 pixels: new ArrayBuffer(8), 432 offset: 0, 433 stride: 8, 434 region: { size: { height: 1,width:2 }, x: 0, y: 0 } 435} 436``` 437 438**After adaptation** 439 440```typescript 441import image from '@ohos.multimedia.image'; 442 443const area: image.PositionArea = { 444 pixels: new ArrayBuffer(8), 445 offset: 0, 446 stride: 8, 447 region: { size: { height: 1, width: 2 }, x: 0, y: 0 } 448} 449``` 450 451### Using a Class for Object Literal Type Annotation Only When the Class Constructor Have No Parameters 452 453**Before adaptation** 454 455```typescript 456class Test { 457 value: number = 1 458 459 constructor(value: number) { 460 this.value = value; 461 } 462} 463 464let t: Test = { value: 2 }; 465``` 466 467**After adaptation: mode 1** 468 469```typescript 470// Remove the constructor. 471class Test { 472 value: number = 1 473} 474 475let t: Test = { value: 2 }; 476``` 477 478**After adaptation: mode 2** 479```typescript 480// Use new. 481class Test { 482 value: number = 1 483 484 constructor(value: number) { 485 this.value = value; 486 } 487} 488 489let t: Test = new Test(2); 490``` 491 492**Reason for change** 493 494```typescript 495class C { 496 value: number = 1 497 498 constructor(n: number) { 499 if (n < 0) { 500 throw new Error('Negative'); 501 } 502 this.value = n; 503 } 504} 505 506let s: C = new C(-2); // An exception is thrown. 507let t: C = { value: -2 }; // Not supported by ArkTS. 508``` 509 510In the preceding example, if **C** is allowed to be used to specify the object literal type, the variable **t** in the code will cause ambiguity of behavior. In light of this, ArkTS does not allow for object literal type annotation that may cause this issue. 511 512### Using an Identifier as the Object Literal Key When Specifying the Object Literal Type with a Class or Interface 513 514**Before adaptation** 515 516```typescript 517class Test { 518 value: number = 0 519} 520 521let arr: Test[] = [ 522 { 523 'value': 1 524 }, 525 { 526 'value': 2 527 }, 528 { 529 'value': 3 530 } 531] 532``` 533 534**After adaptation** 535 536```typescript 537class Test { 538 value: number = 0 539} 540let arr: Test[] = [ 541 { 542 value: 1 543 }, 544 { 545 value: 2 546 }, 547 { 548 value: 3 549 } 550] 551``` 552 553### Using a Key String for Object Literals of the Record Type 554 555If an object literal is of the Record type, a string must be used as the key of the object literal. 556 557**Before adaptation** 558 559```typescript 560let obj: Record<string, number | string> = { 561 value: 123, 562 name: 'abc' 563} 564``` 565 566**After adaptation** 567 568```typescript 569let obj: Record<string, number | string> = { 570 'value': 123, 571 'name': 'abc' 572} 573``` 574 575### Including Index Signature in the Function Parameter Type 576 577**Before adaptation** 578 579```typescript 580function foo(obj: { [key: string]: string}): string { 581 if (obj != undefined && obj != null) { 582 return obj.value1 + obj.value2; 583 } 584 return ''; 585} 586``` 587 588**After adaptation** 589 590```typescript 591function foo(obj: Record<string, string>): string { 592 if (obj != undefined && obj != null) { 593 return obj.value1 + obj.value2; 594 } 595 return ''; 596} 597``` 598 599### Including Object Literals in Actual Parameters of Functions 600 601**Before adaptation** 602 603```typescript 604(fn) => { 605 fn({ value: 123, name:'' }); 606} 607``` 608 609**After adaptation** 610 611```typescript 612class T { 613 value: number = 0 614 name: string = '' 615} 616 617(fn: (v: T) => void) => { 618 fn({ value: 123, name: '' }); 619} 620``` 621 622### Including Methods in Classes or Interfaces 623 624**Before adaptation** 625 626```typescript 627interface T { 628 foo(value: number): number 629} 630 631let t:T = { foo: (value) => { return value } }; 632``` 633 634**After adaptation: mode 1** 635 636```typescript 637interface T { 638 foo: (value: number) => number 639} 640 641let t:T = { foo: (value) => { return value } }; 642``` 643 644**After adaptation: mode 2** 645 646```typescript 647class T { 648 foo: (value: number) => number = (value: number) => { 649 return value; 650 } 651} 652 653let t:T = new T(); 654``` 655 656**Reason for change** 657 658The methods declared in a class or interface should be shared by all instances of the class. In ArkTS, object literals cannot be used to rewrite instance methods. ArkTS supports attributes of the function type. 659 660### export default Object 661 662**Before adaptation** 663 664```typescript 665import hilog from '@ohos.hilog' 666 667export default { 668 onCreate() { 669 hilog.info(0x0000, 'testTag', '%{public}s', 'Application onCreate'); 670 }, 671 onDestroy() { 672 hilog.info(0x0000, 'testTag', '%{public}s', 'Application onDestroy'); 673 } 674} 675``` 676 677**After adaptation** 678 679```typescript 680import hilog from '@ohos.hilog' 681 682class Test { 683 onCreate() { 684 hilog.info(0x0000, 'testTag', '%{public}s', 'Application onCreate'); 685 } 686 onDestroy() { 687 hilog.info(0x0000, 'testTag', '%{public}s', 'Application onDestroy'); 688 } 689} 690 691export default new Test() 692``` 693 694### Obtaining the Type by Importing a Namespace 695 696**Before adaptation** 697 698```typescript 699import { BusinessError } from '@ohos.base'; 700import bluetooth from '@ohos.bluetooth'; 701let serverNumber = -1; 702function serverSocket(code: BusinessError, num: number) { 703 console.log('bluetooth error code: ' + code.code); 704 if (code.code == 0) { 705 console.log('bluetooth serverSocket Number: ' + num); 706 serverNumber = num; 707 } 708} 709 710let sppOption = { uuid: '', secure: false, type: 0 }; 711bluetooth.sppListen('', sppOption, serverSocket); 712``` 713 714**After adaptation** 715 716```typescript 717import { BusinessError } from '@ohos.base'; 718import bluetooth from '@ohos.bluetooth'; 719let serverNumber = -1; 720function serverSocket(code: BusinessError, num: number) { 721 console.log('bluetooth error code: ' + code.code); 722 if (code.code == 0) { 723 console.log('bluetooth serverSocket Number: ' + num); 724 serverNumber = num; 725 } 726} 727 728let sppOption: bluetooth.SppOption = { uuid: '', secure: false, type: 0 }; 729bluetooth.sppListen('', sppOption, serverSocket); 730``` 731 732**Reason for change** 733 734The object literal lacks a type. According to the analysis of **bluetooth.sppListen**, the **sppOption** type comes from the SDK. Therefore, you only need to import the type. 735In **@ohos.bluetooth**, **sppOption** is defined in the namespace. Therefore, to import the type in the .ets file, import the namespace and then obtain the target type based on the name. 736 737### Passing Parameters from the Object Literal to the Object Type 738 739**Before adaptation** 740 741```typescript 742function emit(event: string, ...args: Object[]): void {} 743 744emit('', { 745 'action': 11, 746 'outers': false 747}); 748``` 749 750**After adaptation** 751 752```typescript 753function emit(event: string, ...args: Object[]): void {} 754 755let emitArg: Record<string, number | boolean> = { 756 'action': 11, 757 'outers': false 758} 759 760emit('', emitArg); 761``` 762 763## arkts-no-obj-literals-as-types 764 765**Before adaptation** 766 767```typescript 768type Person = { name: string, age: number } 769``` 770 771**After adaptation** 772 773```typescript 774interface Person { 775 name: string, 776 age: number 777} 778``` 779 780## arkts-no-noninferrable-arr-literals 781 782**Before adaptation** 783 784```typescript 785let permissionList = [ 786 {name: 'Device information', value: 'Used to analyze the battery life, call, Internet access, and SIM card issues of the device.'}, 787 {name: 'Microphone', value: 'Used to add voice when reporting an issue.'}, 788 {"name: 'Storage', value: 'Used to add local file attachments when reporting an issue.'} 789] 790``` 791 792**After adaptation** 793 794Declare the type for the object literal. 795 796```typescript 797class PermissionItem { 798 name?: string 799 value?: string 800} 801 802let permissionList: PermissionItem[] = [ 803 {name: 'Device information', value: 'Used to analyze the battery life, call, Internet access, and SIM card issues of the device.'}, 804 {name: 'Microphone', value: 'Used to add voice when reporting an issue.'}, 805 {"name: 'Storage', value: 'Used to add local file attachments when reporting an issue.'} 806] 807``` 808 809## arkts-no-method-reassignment 810 811**Before adaptation** 812 813```typescript 814class C { 815 add(left: number, right: number): number { 816 return left + right; 817 } 818} 819 820function sub(left: number, right: number): number { 821 return left - right; 822} 823 824let c1 = new C(); 825c1.add = sub; 826``` 827 828**After adaptation** 829 830```typescript 831class C { 832 add: (left: number, right: number) => number = 833 (left: number, right: number) => { 834 return left + right; 835 } 836} 837 838function sub(left: number, right: number): number { 839 return left - right; 840} 841 842let c1 = new C(); 843c1.add = sub; 844``` 845 846## arkts-no-polymorphic-unops 847 848**Before adaptation** 849 850```typescript 851let a = +'5'; 852let b = -'5'; 853let c = ~'5'; 854let d = +'string'; 855``` 856 857**After adaptation** 858 859```typescript 860let a = Number.parseInt('5'); 861let b = -Number.parseInt('5'); 862let c = ~Number.parseInt('5'); 863let d = new Number('string'); 864``` 865 866## arkts-no-type-query 867 868**Before adaptation** 869 870```typescript 871// module1.ts 872class C { 873 value: number = 0 874} 875 876export let c = new C() 877 878// module2.ts 879import { c } from './module1' 880let t: typeof c = { value: 123 }; 881``` 882 883**After adaptation** 884 885```typescript 886// module1.ts 887class C { 888 value: number = 0 889} 890 891export { C } 892 893// module2.ts 894import { C } from './module1' 895let t: C = { value: 123 }; 896``` 897 898## arkts-no-in 899 900### Using Object.keys to Determine Whether an Attribute Exists 901 902**Before adaptation** 903 904```typescript 905function test(str: string, obj: Record<string, Object>) { 906 return str in obj; 907} 908``` 909 910**After adaptation** 911 912```typescript 913function test(str: string, obj: Record<string, Object>) { 914 for (let i of Object.keys(obj)) { 915 if (i == str) { 916 return true; 917 } 918 } 919 return false; 920} 921``` 922 923## arkts-no-destruct-assignment 924 925**Before adaptation** 926 927```typescript 928let map = new Map<string, string>([['a', 'a'], ['b', 'b']]); 929for (let [key, value] of map) { 930 console.log(key); 931 console.log(value); 932} 933``` 934 935**After adaptation** 936 937Use arrays. 938 939```typescript 940let map = new Map<string, string>([['a', 'a'], ['b', 'b']]); 941for (let arr of map) { 942 let key = arr[0]; 943 let value = arr[1]; 944 console.log(key); 945 console.log(value); 946} 947``` 948 949## arkts-no-types-in-catch 950 951**Before adaptation** 952 953```typescript 954import { BusinessError } from '@ohos.base'; 955 956try { 957 // ... 958} catch (e: BusinessError) { 959 logger.error(e.code, e.message); 960} 961``` 962 963**After adaptation** 964 965```typescript 966import { BusinessError } from '@ohos.base'; 967 968try { 969 // ... 970} catch (error) { 971 let e: BusinessError = error as BusinessError; 972 logger.error(e.code, e.message); 973} 974``` 975 976## arkts-no-for-in 977 978**Before adaptation** 979 980```typescript 981interface Person { 982 [name: string]: string 983} 984let p: Person = { 985 name: 'tom', 986 age: '18' 987}; 988 989for (let t in p) { 990 console.log(p[t]); 991} 992``` 993 994**After adaptation** 995 996```typescript 997let p: Record<string, string> = { 998 'name': 'tom', 999 'age': '18' 1000}; 1001 1002for (let ele of Object.entries(p)) { 1003 console.log(ele[1]); 1004} 1005``` 1006 1007## arkts-no-mapped-types 1008 1009**Before adaptation** 1010 1011```typescript 1012class C { 1013 a: number = 0 1014 b: number = 0 1015 c: number = 0 1016} 1017type OptionsFlags = { 1018 [Property in keyof C]: string 1019} 1020``` 1021 1022**After adaptation** 1023 1024```typescript 1025class C { 1026 a: number = 0 1027 b: number = 0 1028 c: number = 0 1029} 1030 1031type OptionsFlags = Record<keyof C, string> 1032``` 1033 1034## arkts-limited-throw 1035 1036**Before adaptation** 1037 1038```typescript 1039import { BusinessError } from '@ohos.base'; 1040 1041function ThrowError(error: BusinessError) { 1042 throw error; 1043} 1044``` 1045 1046**After adaptation** 1047 1048```typescript 1049import { BusinessError } from '@ohos.base'; 1050 1051function ThrowError(error: BusinessError) { 1052 throw error as Error; 1053} 1054``` 1055 1056**Reason for change** 1057 1058The type of the value in the **throw** statement must be **Error** or its inheritance class. If the inheritance class is a generic, an error is reported during compilation. You are advised to use **as** to convert the type to **Error**. 1059 1060## arkts-no-standalone-this 1061 1062### Using this in a Function 1063 1064**Before adaptation** 1065 1066```typescript 1067function foo() { 1068 console.log(this.value); 1069} 1070 1071let obj = { value: 'abc' }; 1072foo.apply(obj); 1073``` 1074 1075**After adaptation: mode 1** 1076 1077Use the method of a class. If the method is used by multiple classes, consider using the inheritance mechanism. 1078 1079```typescript 1080class Test { 1081 value: string = '' 1082 constructor (value: string) { 1083 this.value = value 1084 } 1085 1086 foo() { 1087 console.log(this.value); 1088 } 1089} 1090 1091let obj: Test = new Test('abc'); 1092obj.foo(); 1093``` 1094 1095**After adaptation: mode 2** 1096 1097Passing this as a Parameter 1098 1099```typescript 1100function foo(obj: Test) { 1101 console.log(obj.value); 1102} 1103 1104class Test { 1105 value: string = '' 1106} 1107 1108let obj: Test = { value: 'abc' }; 1109foo(obj); 1110``` 1111 1112**After adaptation: mode 3** 1113 1114Pass the attribute as a parameter. 1115```typescript 1116function foo(value: string) { 1117 console.log(value); 1118} 1119 1120class Test { 1121 value: string = '' 1122} 1123 1124let obj: Test = { value: 'abc' }; 1125foo(obj.value); 1126``` 1127 1128### Using this in the Static Method of a Class 1129 1130**Before adaptation** 1131 1132```typescript 1133class Test { 1134 static value: number = 123 1135 static foo(): number { 1136 return this.value 1137 } 1138} 1139``` 1140 1141**After adaptation** 1142 1143```typescript 1144class Test { 1145 static value: number = 123 1146 static foo(): number { 1147 return Test.value 1148 } 1149} 1150``` 1151 1152## arkts-no-spread 1153 1154**Before adaptation** 1155 1156```typescript 1157import notification from '@ohos.notificationManager'; 1158 1159function buildNotifyLongRequest(): notification.NotificationRequest { 1160 // ... 1161} 1162 1163let notificationRequest: notification.NotificationRequest = { 1164 ...buildNotifyLongRequest(), 1165 deliveryTime: new Date().getTime() 1166} 1167``` 1168 1169**After adaptation** 1170 1171```typescript 1172import notification from '@ohos.notificationManager'; 1173 1174function buildNotifyLongRequest():notification.NotificationRequest { 1175 // ... 1176} 1177 1178let notificationRequest: notification.NotificationRequest = buildNotifyLongRequest(); 1179notificationRequest.deliveryTime = new Date().getTime(); 1180``` 1181 1182**Reason for change** 1183 1184In ArkTS, the object layout is determined at compile time. To assign all attributes of an object to another object, you can use the attribute-by-attribute assignment statement. In this example, the type of the source object s the same as that of the target object. In this case, you can reconstruct the code by changing the object attribute. 1185 1186## arkts-no-ctor-signatures-funcs 1187 1188Declare attributes within a class, not on a constructor. 1189 1190**Before adaptation** 1191 1192```typescript 1193class Controller { 1194 value: string = '' 1195 constructor(value: string) { 1196 this.value = value 1197 } 1198} 1199 1200type ControllerConstructor = new (value: string) => Controller; 1201 1202class Menu { 1203 controller: ControllerConstructor = Controller 1204 createController() { 1205 if (this.controller) { 1206 return new this.controller('abc'); 1207 } 1208 return null; 1209 } 1210} 1211 1212let t = new Menu() 1213console.log(t.createController()!.value) 1214``` 1215 1216**After adaptation** 1217 1218```typescript 1219class Controller { 1220 value: string = '' 1221 constructor(value: string) { 1222 this.value = value; 1223 } 1224} 1225 1226type ControllerConstructor = () => Controller; 1227 1228class Menu { 1229 controller: ControllerConstructor = () => { return new Controller('abc') } 1230 createController() { 1231 if (this.controller) { 1232 return this.controller(); 1233 } 1234 return null; 1235 } 1236} 1237 1238let t: Menu = new Menu(); 1239console.log(t.createController()!.value); 1240``` 1241 1242## arkts-no-globalthis 1243 1244ArkTS does not support **globalThis** for two reasons:<br>(1) A static type cannot be added for **globalThis**. As a result, the attributes of **globalThis** can be accessed only through search, which causes extra performance overhead.<br> (2) Type annotation is not available for attributes of **globalThis**. As a result, the security and performance of operations on these attributes cannot be ensured. 1245 12461. You are advised to transfer data between modules based on the service logic and import/export syntax. 1247 12482. If necessary, you can construct a singleton object to implement the function of a global object. (Note: The singleton object cannot be defined in a HAR file, which packs two copies in different HAP files and therefore cannot implement singleton objects.) 1249 1250Construct a singleton object. 1251 1252```typescript 1253// Construct a singleton object. 1254export class GlobalContext { 1255 private constructor() {} 1256 private static instance: GlobalContext; 1257 private _objects = new Map<string, Object>(); 1258 1259 public static getContext(): GlobalContext { 1260 if (!GlobalContext.instance) { 1261 GlobalContext.instance = new GlobalContext(); 1262 } 1263 return GlobalContext.instance; 1264 } 1265 1266 getObject(value: string): Object | undefined { 1267 return this._objects.get(value); 1268 } 1269 1270 setObject(key: string, objectClass: Object): void { 1271 this._objects.set(key, objectClass); 1272 } 1273} 1274 1275``` 1276 1277**Before adaptation** 1278 1279```typescript 1280 1281// file1.ts 1282 1283export class Test { 1284 value: string = ''; 1285 foo(): void { 1286 globalThis.value = this.value; 1287 } 1288} 1289 1290// file2.ts 1291 1292globalThis.value; 1293 1294``` 1295 1296**After adaptation** 1297 1298```typescript 1299 1300// file1.ts 1301 1302import { GlobalContext } from '../GlobalContext' 1303 1304export class Test { 1305 value: string = ''; 1306 foo(): void { 1307 GlobalContext.getContext().setObject('value', this.value); 1308 } 1309} 1310 1311// file2.ts 1312 1313import { GlobalContext } from '../GlobalContext' 1314 1315GlobalContext.getContext().getObject('value'); 1316``` 1317 1318## arkts-no-func-apply-bind-call 1319 1320### Using Interfaces in the Standard Library 1321 1322**Before adaptation** 1323 1324```typescript 1325let arr: number[] = [1, 2, 3, 4]; 1326let str = String.fromCharCode.apply(null, Array.from(arr)); 1327``` 1328 1329**After adaptation** 1330 1331```typescript 1332let arr: number[] = [1, 2, 3, 4]; 1333let str = String.fromCharCode(...Array.from(arr)); 1334``` 1335 1336### Using bind in Method Definitions 1337 1338**Before adaptation** 1339 1340```typescript 1341class A { 1342 value: string = '' 1343 foo: Function = () => {} 1344} 1345 1346class Test { 1347 value: string = '1234' 1348 obj: A = { 1349 value: this.value, 1350 foo: this.foo.bind(this) 1351 } 1352 1353 foo() { 1354 console.log(this.value); 1355 } 1356} 1357``` 1358 1359**After adaptation: mode 1** 1360 1361```typescript 1362class A { 1363 value: string = '' 1364 foo: Function = () => {} 1365} 1366 1367class Test { 1368 value: string = '1234' 1369 obj: A = { 1370 value: this.value, 1371 foo: (): void => this.foo() 1372 } 1373 1374 foo() { 1375 console.log(this.value); 1376 } 1377} 1378``` 1379 1380**After adaptation: mode 2** 1381 1382```typescript 1383class A { 1384 value: string = '' 1385 foo: Function = () => {} 1386} 1387 1388class Test { 1389 value: string = '1234' 1390 foo: () => void = () => { 1391 console.log(this.value); 1392 } 1393 obj: A = { 1394 value: this.value, 1395 foo: this.foo 1396 } 1397} 1398``` 1399 1400### Using apply 1401 1402**Before adaptation** 1403 1404```typescript 1405class A { 1406 value: string; 1407 constructor (value: string) { 1408 this.value = value; 1409 } 1410 1411 foo() { 1412 console.log(this.value); 1413 } 1414} 1415 1416let a1 = new A('1'); 1417let a2 = new A('2'); 1418 1419a1.foo(); 1420a1.foo.apply(a2); 1421``` 1422 1423**After adaptation** 1424 1425```typescript 1426class A { 1427 value: string; 1428 constructor (value: string) { 1429 this.value = value; 1430 } 1431 1432 foo() { 1433 this.fooApply(this); 1434 } 1435 1436 fooApply(a: A) { 1437 console.log(a.value); 1438 } 1439} 1440 1441let a1 = new A('1'); 1442let a2 = new A('2'); 1443 1444a1.foo(); 1445a1.fooApply(a2); 1446``` 1447 1448## arkts-limited-stdlib 1449 1450### `Object.fromEntries()` 1451 1452**Before adaptation** 1453 1454```typescript 1455let entries = new Map([ 1456 ['foo', 123], 1457 ['bar', 456] 1458]); 1459 1460let obj = Object.fromEntries(entries); 1461``` 1462 1463**After adaptation** 1464 1465```typescript 1466let entries = new Map([ 1467 ['foo', 123], 1468 ['bar', 456] 1469]); 1470 1471let obj: Record<string, Object> = {}; 1472entries.forEach((value, key) => { 1473 if (key != undefined && key != null) { 1474 obj[key] = value; 1475 } 1476}) 1477``` 1478 1479### Using Attributes and Methods of Number 1480 1481ArkTS does not allow the use of the following attributes and methods for global objects: **Infinity**, **NaN**, **isFinite**, **isNaN**, **parseFloat**, and **parseInt** 1482 1483You can use them for **Number**. 1484 1485**Before adaptation** 1486 1487```typescript 1488NaN; 1489isFinite(123); 1490parseInt('123'); 1491``` 1492 1493**After adaptation** 1494 1495```typescript 1496Number.NaN; 1497Number.isFinite(123); 1498Number.parseInt('123'); 1499``` 1500 1501## arkts-strict-typing(StrictModeError) 1502 1503### strictPropertyInitialization 1504 1505**Before adaptation** 1506 1507```typescript 1508interface I { 1509 name:string 1510} 1511 1512class A {} 1513 1514class Test { 1515 a: number; 1516 b: string; 1517 c: boolean; 1518 d: I; 1519 e: A; 1520} 1521 1522``` 1523 1524**After adaptation** 1525 1526```typescript 1527interface I { 1528 name:string 1529} 1530 1531class A {} 1532 1533class Test { 1534 a: number; 1535 b: string; 1536 c: boolean; 1537 d: I = { name:'abc' }; 1538 e: A | null = null; 1539 constructor(a:number, b:string, c:boolean) { 1540 this.a = a; 1541 this.b = b; 1542 this.c = c; 1543 } 1544} 1545 1546``` 1547### Type '*** | null' Not Assignable to type ''\*\*\*' 1548 1549**Before adaptation** 1550 1551```typescript 1552class A { 1553 bar() {} 1554} 1555function foo(n: number) { 1556 if (n === 0) { 1557 return null; 1558 } 1559 return new A(); 1560} 1561function getNumber() { 1562 return 5; 1563} 1564let a:A = foo(getNumber()); 1565a.bar(); 1566``` 1567 1568**After adaptation** 1569 1570```typescript 1571class A { 1572 bar() {} 1573} 1574function foo(n: number) { 1575 if (n === 0) { 1576 return null; 1577 } 1578 return new A(); 1579} 1580function getNumber() { 1581 return 5; 1582} 1583 1584let a: A | null = foo(getNumber()); 1585a?.bar(); 1586``` 1587 1588### Strict Attribute Initialization Check 1589 1590In a class, if an attribute is not initialized and is not assigned a value in the constructor, ArkTS reports an error. 1591 1592**After adaptation** 1593 15941. Whenever possible, initialize attributes during declaration based on service logic or assign values to the attributes in constructors. Example: 1595 1596```typescript 1597//code with error 1598class Test { 1599 value: number 1600 flag: boolean 1601} 1602 1603// Method 1: Initialize attributes during declaration. 1604class Test { 1605 value: number = 0 1606 flag: boolean = false 1607} 1608 1609// Method 2: Assign values to attributes in the constructor. 1610class Test { 1611 value: number 1612 flag: boolean 1613 constructor(value: number, flag: boolean) { 1614 this.value = value; 1615 this.flag = flag; 1616 } 1617} 1618``` 1619 16202. For object type (including function type) **A**, if you are not sure how to initialize it, you are advised to initialize it in one of the following ways: 1621 1622 Mode (i): **prop: A | null = null** 1623 1624 Mode (ii): **prop?:A** 1625 1626 Mode 3 (iii): **prop: A | undefined = undefined** 1627 1628- From the perspective of performance, the **null** type is used only for type check during compilation and has no impact on VM performance. In contrast, **undefined | A** is treated as a union type and may result in additional overhead at run time. 1629- In terms of code readability and simplicity, **prop?:A** is the syntax sugar of **prop: A | undefined = undefined**. You are advised to use optional attributes. 1630 1631### Strict Function Type Check 1632 1633**Before adaptation** 1634 1635```typescript 1636function foo(fn: (value?: string) => void, value: string): void {} 1637 1638foo((value: string) => {}, ''); //error 1639``` 1640 1641**After adaptation** 1642 1643```typescript 1644function foo(fn: (value?: string) => void, value: string): void {} 1645 1646foo((value?: string) => {}, ''); 1647``` 1648 1649**Reason for change** 1650 1651In the following example, if strict function type check is not enabled during compilation, the code can be compiled successfully, but unexpected behavior occurs at run time. Specifically, in the function body of **foo**, an **undefined** is passed in to **fn** (this is acceptable because **fn** can accept **undefined**). However, at the invoking point of **foo** in line 6 of the code, in the passed function implementation of **(value: string) => { console.log(value.toUpperCase()) }**, the **value** parameter is always of the string type and can call the **toUpperCase** method. If strict function type check is not enabled, an error indicating that the property cannot be found on **undefined** occurs at run time. 1652 1653```typescript 1654function foo(fn: (value?: string) => void, value: string): void { 1655 let v: string | undefined = undefined; 1656 fn(v); 1657} 1658 1659foo((value: string) => { console.log(value.toUpperCase()) }, ''); // Cannot read properties of undefined (reading 'toUpperCase') 1660``` 1661 1662If strict type check is enabled during compilation, the preceding issue can be detected at compile time. 1663 1664### Strict Null Check 1665 1666**Before adaptation** 1667 1668```typescript 1669class Test { 1670 private value?: string 1671 1672 public printValue () { 1673 console.log(this.value.toLowerCase()); 1674 } 1675} 1676 1677let t = new Test(); 1678t.printValue(); 1679``` 1680 1681**After adaptation** 1682 1683When writing code, minimize the use of nullable types. If a variable or property is marked with a nullable type, a null check is required. Process the service logic based on whether the variable or property is null. 1684 1685```typescript 1686class Test { 1687 private value?: string 1688 1689 public printValue () { 1690 if (this.value) { 1691 console.log(this.value.toLowerCase()); 1692 } 1693 } 1694} 1695 1696let t = new Test(); 1697t.printValue(); 1698``` 1699 1700**Reason for change** 1701 1702In the first code segment, if strict null check is not enabled during compilation, the code segment can be compiled successfully, but unexpected behavior occurs at run time. This is because the **value** property of **t** is **undefined** (**value?: string** is the syntax sugar of **value: string | undefined = undefined**), and when the **printValue** method is called in line 11, the property is directly accessed based on the string type, due to a lack of null check on the value of **this.value** in the method body. To avoid unexpected behavior at run time, enable strict null check during compilation. 1703 1704### Function Return Type Mismatch 1705 1706**Before adaptation** 1707 1708```typescript 1709class Test { 1710 handleClick: (action: string, externInfo?: string) => void | null = null; 1711} 1712``` 1713 1714**After adaptation** 1715 1716In the original code, the return type of the function is parsed as **void | undefined**. Add parentheses to distinguish the union type. 1717 1718```typescript 1719class Test { 1720 handleClick: ((action: string, externInfo?: string) => void) | null = null; 1721} 1722``` 1723 1724### '***' Is of Type 'unknown' 1725 1726**Before adaptation** 1727 1728```typescript 1729try { 1730 1731} catch (error) { 1732 console.log(error.message); 1733} 1734``` 1735 1736**After adaptation** 1737 1738```typescript 1739import { BusinessError } from '@ohos.base' 1740 1741try { 1742 1743} catch (error) { 1744 console.log((error as BusinessError).message); 1745} 1746``` 1747 1748### Type '*** | null' Not Assignable to Type '\*\*\*' 1749 1750**Before adaptation** 1751 1752```typescript 1753class A { 1754 value: number 1755 constructor(value: number) { 1756 this.value = value; 1757 } 1758} 1759 1760function foo(v: number): A | null { 1761 if (v > 0) { 1762 return new A(v); 1763 } 1764 return null; 1765} 1766 1767let a: A = foo(); 1768``` 1769 1770**After adaptation: mode 1** 1771 1772Change the type of variable **a** to **let a: A | null = foo()**. 1773 1774```typescript 1775class A { 1776 value: number 1777 constructor(value: number) { 1778 this.value = value; 1779 } 1780} 1781 1782function foo(v: number): A | null { 1783 if (v > 0) { 1784 return new A(v); 1785 } 1786 return null; 1787} 1788 1789let a: A | null = foo(123); 1790 1791if (a != null) { 1792 // Non-empty branch 1793} else { 1794 // Process null. 1795} 1796``` 1797 1798**After adaptation: mode 2** 1799 1800If you can determine that a non-null value is returned when **foo** is called, you can use a non-null assertion operator **!**. 1801 1802```typescript 1803class A { 1804 value: number 1805 constructor(value: number) { 1806 this.value = value; 1807 } 1808} 1809 1810function foo(v: number): A | null { 1811 if (v > 0) { 1812 return new A(v); 1813 } 1814 return null; 1815} 1816 1817let a: A = foo(123)!; 1818``` 1819 1820### Cannot Invoke an Object Which Is Possibly 'undefined' 1821 1822**Before adaptation** 1823 1824```typescript 1825interface A { 1826 foo?: () => void 1827} 1828 1829let a:A = { foo: () => {} }; 1830a.foo(); 1831``` 1832 1833**After adaptation: mode 1** 1834 1835```typescript 1836interface A { 1837 foo: () => void 1838} 1839let a: A = { foo: () => {} }; 1840a.foo(); 1841``` 1842 1843**After adaptation: mode 2** 1844 1845```typescript 1846interface A { 1847 foo?: () => void 1848} 1849 1850let a: A = { foo: () => {} }; 1851if (a.foo) { 1852 a.foo(); 1853} 1854``` 1855 1856**Reason for change** 1857 1858In the original code definition, **foo** is an optional property and may be **undefined**. If **undefined** is called, an error is reported. You are advised to determine whether a property is optional based on the service logic. If defining an optional property is necessary, a null check is required for accessing the property. 1859 1860### Variable '***' Is Used Before Being Assigned 1861 1862**Before adaptation** 1863 1864```typescript 1865class Test { 1866 value: number = 0 1867} 1868 1869let a: Test 1870try { 1871 a = { value: 1}; 1872} catch (e) { 1873 a.value; 1874} 1875a.value; 1876``` 1877 1878**After adaptation** 1879 1880```typescript 1881class Test { 1882 value: number = 0 1883} 1884 1885let a: Test | null = null; 1886try { 1887 a = { value:1 }; 1888} catch (e) { 1889 if (a) { 1890 a.value; 1891 } 1892} 1893 1894if (a) { 1895 a.value; 1896} 1897``` 1898 1899**Reason for change** 1900 1901For primitive types, a value can be assigned based on the service logic, for example, **0**, **''**, and **false**. 1902 1903For the object type, you can change the type to a union type consisting of **null** and assign **null** to the type. In this case, when using the object type, you need to perform the non-null check. 1904 1905### "Function lacks ending return statement and return type does not include 'undefined'" Error 1906 1907**Before adaptation** 1908 1909```typescript 1910function foo(a: number): number { 1911 if (a > 0) { 1912 return a; 1913 } 1914} 1915``` 1916 1917**After adaptation: mode 1** 1918 1919Return a proper value in the **else** branch based on the service logic. 1920 1921**After adaptation: mode 2** 1922 1923```typescript 1924function foo(a: number): number | undefined { 1925 if (a > 0) { 1926 return a; 1927 } 1928 return 1929} 1930``` 1931 1932## arkts-strict-typing-required 1933 1934**Before adaptation** 1935 1936```typescript 1937// @ts-nocheck 1938var a: any = 123; 1939``` 1940 1941**After adaptation** 1942 1943```typescript 1944let a: number = 123; 1945``` 1946 1947**Reason for change** 1948 1949ArkTS does not support the use of comments to bypass strict type checks. Delete the comment (**// @ts-nocheck** or **// @ts-ignore**), and then modify other code based on the error information. 1950 1951## Importing ArkTS Files to JS and TS Files Not Allowed 1952 1953## arkts-no-tsdeps 1954 1955In .ts and .js files, it is not allowed to import source code from an .ets file. 1956 1957**After adaptation** 1958 1959Mode 1: Change the file name extension of the .ts file to .ets and adapt the code based on the ArkTS syntax rules. 1960 1961Mode 2: Extract the code on which the .ts file depends from the .ets file to the .ts file. 1962 1963## arkts-no-special-imports 1964 1965**Before adaptation** 1966 1967```typescript 1968import type {A, B, C, D } from '***' 1969``` 1970 1971 1972**After adaptation** 1973 1974```typescript 1975import {A, B, C, D } from '***' 1976``` 1977 1978## arkts-no-classes-as-obj 1979 1980### Using Class to Construct an Instance 1981 1982**Before adaptation** 1983 1984```typescript 1985class Controller { 1986 value: string = '' 1987 constructor(value: string) { 1988 this.value = value 1989 } 1990} 1991 1992interface ControllerConstructor { 1993 new (value: string): Controller; 1994} 1995 1996class Menu { 1997 controller: ControllerConstructor = Controller 1998 createController() { 1999 if (this.controller) { 2000 return new this.controller('abc'); 2001 } 2002 return null; 2003 } 2004} 2005 2006let t = new Menu(); 2007console.log(t.createController()!.value); 2008``` 2009 2010**After adaptation** 2011 2012```typescript 2013class Controller { 2014 value: string = '' 2015 constructor(value: string) { 2016 this.value = value 2017 } 2018} 2019 2020type ControllerConstructor = () => Controller; 2021 2022class Menu { 2023 controller: ControllerConstructor = () => { return new Controller('abc'); } 2024 createController() { 2025 if (this.controller) { 2026 return this.controller(); 2027 } 2028 return null; 2029 } 2030} 2031 2032let t: Menu = new Menu(); 2033console.log(t.createController()!.value); 2034``` 2035 2036### Accessing Static Properties 2037 2038**Before adaptation** 2039 2040```typescript 2041class C1 { 2042 static value: string = 'abc' 2043} 2044 2045class C2 { 2046 static value: string = 'def' 2047} 2048 2049function getValue(obj: any) { 2050 return obj['value']; 2051} 2052 2053console.log(getValue(C1)); 2054console.log(getValue(C2)); 2055``` 2056 2057**After adaptation** 2058 2059```typescript 2060class C1 { 2061 static value: string = 'abc' 2062} 2063 2064class C2 { 2065 static value: string = 'def' 2066} 2067 2068function getC1Value(): string { 2069 return C1.value; 2070} 2071 2072function getC2Value(): string { 2073 return C2.value; 2074} 2075 2076console.log(getC1Value()); 2077console.log(getC2Value()); 2078``` 2079 2080## arkts-no-side-effects-imports 2081 2082Use Dynamic Imports 2083 2084**Before adaptation** 2085 2086```typescript 2087import 'module' 2088``` 2089 2090**After adaptation** 2091 2092```typescript 2093import('module') 2094``` 2095 2096## arkts-no-func-props 2097 2098**Before adaptation** 2099 2100```typescript 2101function foo(value: number): void { 2102 console.log(value.toString()); 2103} 2104 2105foo.add = (left: number, right: number) => { 2106 return left + right; 2107} 2108 2109foo.sub = (left: number, right: number) => { 2110 return left - right; 2111} 2112``` 2113 2114**After adaptation** 2115 2116```typescript 2117class Foo { 2118 static foo(value: number): void { 2119 console.log(value.toString()); 2120 } 2121 2122 static add(left: number, right: number): number { 2123 return left + right; 2124 } 2125 2126 static sub(left: number, right: number): number { 2127 return left - right; 2128 } 2129} 2130``` 2131 2132## Typical Application Scenarios of State Management 2133 2134### Using State Variables Outside of Structs 2135 2136The struct is different from the class. Therefore, avoid passing **this** as a parameter to the outside of the struct. Otherwise, the instance reference cannot be released and memory leakage may occur. You are advised to pass the state variable object outside the struct and modify the object properties to trigger UI re-render. 2137 2138**Not recommended** 2139 2140```typescript 2141export class MyComponentController { 2142 item: MyComponent = null; 2143 2144 setItem(item: MyComponent) { 2145 this.item = item; 2146 } 2147 2148 changeText(value: string) { 2149 this.item.value = value; 2150 } 2151} 2152 2153@Component 2154export default struct MyComponent { 2155 public controller: MyComponentController = null; 2156 @State value: string = 'Hello World'; 2157 2158 build() { 2159 Column() { 2160 Text(this.value) 2161 .fontSize(50) 2162 } 2163 } 2164 2165 aboutToAppear() { 2166 if (this.controller) 2167 this.controller.setItem(this); 2168 } 2169} 2170 2171@Entry 2172@Component 2173struct ObjThisOldPage { 2174 controller = new MyComponentController(); 2175 2176 build() { 2177 Column() { 2178 MyComponent({ controller: this.controller }) 2179 Button('change value').onClick(() => { 2180 this.controller.changeText('Text'); 2181 }) 2182 } 2183 } 2184} 2185``` 2186 2187**Recommended** 2188 2189```typescript 2190class CC { 2191 value: string = '1'; 2192 2193 constructor(value: string) { 2194 this.value = value; 2195 } 2196} 2197 2198export class MyComponentController { 2199 item: CC = new CC('1'); 2200 2201 setItem(item: CC) { 2202 this.item = item; 2203 } 2204 2205 changeText(value: string) { 2206 this.item.value = value; 2207 } 2208} 2209 2210@Component 2211export default struct MyComponent { 2212 public controller: MyComponentController | null = null; 2213 @State value: CC = new CC('Hello World') 2214 2215 build() { 2216 Column() { 2217 Text(`${this.value.value}`) 2218 .fontSize(50) 2219 } 2220 } 2221 2222 aboutToAppear() { 2223 if (this.controller) 2224 this.controller.setItem(this.value); 2225 } 2226} 2227 2228@Entry 2229@Component 2230struct StyleExample { 2231 controller: MyComponentController = new MyComponentController(); 2232 2233 build() { 2234 Column() { 2235 MyComponent({ controller: this.controller }) 2236 Button('change value').onClick(() => { 2237 this.controller.changeText('Text') 2238 }) 2239 } 2240 } 2241} 2242``` 2243 2244### Using Union Types in Structs 2245 2246The following code contains the arkts-no-any-unknown error. Because the struct does not support generics, you are advised to use the union type to implement generic-like functions of custom components. 2247 2248**Not recommended** 2249 2250```typescript 2251class Data { 2252 aa: number = 11; 2253} 2254 2255@Entry 2256@Component 2257struct DatauionOldPage { 2258 @State array: Data[] = [new Data(), new Data(), new Data()]; 2259 2260 @Builder 2261 componentCloser(data: Data) { 2262 Text(data.aa + '').fontSize(50) 2263 } 2264 2265 build() { 2266 Row() { 2267 Column() { 2268 ForEachCom({ arrayList: this.array, closer: this.componentCloser }) 2269 } 2270 .width('100%') 2271 } 2272 .height('100%') 2273 } 2274} 2275 2276@Component 2277export struct ForEachCom { 2278 arrayList: any[] 2279 @BuilderParam closer: (data: any) => void = this.componentCloser 2280 2281 @Builder 2282 componentCloser() { 2283 } 2284 2285 build() { 2286 Column() { 2287 ForEach(this.arrayList, (item: any) => { 2288 Row() { 2289 this.closer(item) 2290 }.width('100%').height(200).backgroundColor('#eee') 2291 }) 2292 } 2293 } 2294} 2295``` 2296 2297**Recommended** 2298 2299```typescript 2300class Data { 2301 aa: number = 11; 2302} 2303 2304class Model { 2305 aa: string = '11'; 2306} 2307 2308type UnionData = Data | Model 2309 2310@Entry 2311@Component 2312struct DatauionPage { 2313 array: UnionData[] = [new Data(), new Data(), new Data()]; 2314 2315 @Builder 2316 componentCloser(data: UnionData) { 2317 if (data instanceof Data) { 2318 Text(data.aa + '').fontSize(50) 2319 } 2320 } 2321 2322 build() { 2323 Row() { 2324 Column() { 2325 ForEachCom({ arrayList: this.array, closer: this.componentCloser }) 2326 } 2327 .width('100%') 2328 } 2329 .height('100%') 2330 } 2331} 2332 2333@Component 2334export struct ForEachCom { 2335 arrayList: UnionData[] = [new Data(), new Data(), new Data()]; 2336 @BuilderParam closer: (data: UnionData) => void = this.componentCloser 2337 2338 @Builder 2339 componentCloser() { 2340 } 2341 2342 build() { 2343 Column() { 2344 ForEach(this.arrayList, (item: UnionData) => { 2345 Row() { 2346 this.closer(item) 2347 }.width('100%').height(200).backgroundColor('#eee') 2348 }) 2349 } 2350 } 2351} 2352``` 2353