• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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