• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 适配指导案例
2
3本文通过更多应用场景中的案例,提供在ArkTS语法规则下将TS代码适配成ArkTS代码的建议。各章以ArkTS语法规则英文名称命名,每个案例提供适配前的TS代码和适配后的ArkTS代码。
4
5## arkts-identifiers-as-prop-names
6
7**应用代码**
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**建议改法**
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### 按照业务逻辑,将代码中的`any, unknown`改为具体的类型
42
43```typescript
44function printObj(obj: any) {
45  console.log(obj);
46}
47
48printObj('abc');
49```
50
51**建议改法**
52
53```typescript
54function printObj(obj: string) {
55  console.log(obj);
56}
57
58printObj('abc');
59```
60
61### 标注JSON.parse返回值类型
62
63**应用代码**
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**建议改法**
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### 使用Record类型
98
99**应用代码**
100
101```typescript
102function printProperties(obj: any) {
103  console.log(obj.name);
104  console.log(obj.value);
105}
106```
107
108**建议改法**
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
119使用函数类型来替代。
120
121**应用代码**
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**建议改法**
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**应用代码**
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**建议改法**
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
215使用Record类型来替代。
216
217**应用代码**
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**建议改法**
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**应用代码**
240
241```typescript
242class C {
243  getInstance(): this {
244    return this;
245  }
246}
247```
248
249**建议改法**
250
251```typescript
252class C {
253  getInstance(): C {
254    return this;
255  }
256}
257```
258
259## arkts-no-ctor-prop-decls
260
261**应用代码**
262
263```typescript
264class Person {
265  constructor(readonly name: string) {}
266
267  getName(): string {
268    return this.name;
269  }
270}
271```
272
273**建议改法**
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**应用代码**
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**建议改法**
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
351可以转换成Record类型,用来访问对象的属性。
352
353**应用代码**
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**建议改法**
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**应用代码**
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**建议改法**
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**原因**
402
403`(item instanceof C) ? item: null` 需要声明类型为`C | null`,由于编译器无法推导出`map`的泛型类型参数,需要显式标注。
404
405## arkts-no-regexp-literals
406
407**应用代码**
408
409```typescript
410let regex: RegExp = /\s*/g;
411```
412
413**建议改法**
414
415```typescript
416let regexp: RegExp = new RegExp('\\s*','g');
417```
418
419**原因**
420
421如果正则表达式中使用了标志符,需要将其作为`new RegExp()`的参数。
422
423## arkts-no-untyped-obj-literals
424
425### 从SDK中导入类型,标注object literal类型
426
427**应用代码**
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**建议改法**
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### 用class为object literal标注类型,需要class的构造函数无参数
452
453**应用代码**
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**建议改法1**
468
469```typescript
470// 去除构造函数
471class Test {
472  value: number = 1
473}
474
475let t: Test = { value: 2 };
476```
477
478**建议改法2**
479```typescript
480// 使用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**原因**
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); 	//抛出异常
507let t: C = { value: -2 };	//ArkTS不支持
508```
509
510例如在上面的例子中,如果允许使用`C`来标注object literal的类型,那么上述代码中的变量`t`会导致行为的二义性。ArkTS禁止通过object literal来绕过这一行为。
511
512### 用class/interface为object literal标注类型,需要使用identifier作为object literal的key
513
514**应用代码**
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**建议改法**
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### 使用Record为object literal标注类型,需要使用字符串作为object literal的key
554
555**应用代码**
556
557```typescript
558let obj: Record<string, number | string> = {
559  value: 123,
560  name: 'abc'
561}
562```
563
564**建议改法**
565
566```typescript
567let obj: Record<string, number | string> = {
568  'value': 123,
569  'name': 'abc'
570}
571```
572
573### 函数参数类型包含index signature
574
575**应用代码**
576
577```typescript
578function foo(obj: { [key: string]: string}): string {
579  if (obj != undefined && obj != null) {
580    return obj.value1 + obj.value2;
581  }
582  return '';
583}
584```
585
586**建议改法**
587
588```typescript
589function foo(obj: Record<string, string>): string {
590  if (obj != undefined && obj != null) {
591    return obj.value1 + obj.value2;
592  }
593  return '';
594}
595```
596
597### 函数实参使用了object literal
598
599**应用代码**
600
601```typescript
602(fn) => {
603  fn({ value: 123, name:'' });
604}
605```
606
607**建议改法**
608
609```typescript
610class T {
611  value: number = 0
612  name: string = ''
613}
614
615(fn: (v: T) => void) => {
616  fn({ value: 123, name: '' });
617}
618```
619
620### class/interface 中包含方法
621
622**应用代码**
623
624```typescript
625interface T {
626  foo(value: number): number
627}
628
629let t:T = { foo: (value) => { return value } };
630```
631
632**建议改法1**
633
634```typescript
635interface T {
636  foo: (value: number) => number
637}
638
639let t:T = { foo: (value) => { return value } };
640```
641
642**建议改法2**
643
644```typescript
645class T {
646  foo: (value: number) => number = (value: number) => {
647    return value;
648  }
649}
650
651let t:T = new T();
652```
653
654**原因**
655
656class/interface中声明的方法应该被所有class的实例共享。ArkTS不支持通过object literal改写实例方法。ArkTS支持函数类型的属性。
657
658### export default对象
659
660**应用代码**
661
662```typescript
663import hilog from '@ohos.hilog'
664
665export default {
666  onCreate() {
667    hilog.info(0x0000, 'testTag', '%{public}s', 'Application onCreate');
668  },
669  onDestroy() {
670    hilog.info(0x0000, 'testTag', '%{public}s', 'Application onDestroy');
671  }
672}
673```
674
675**建议改法**
676
677```typescript
678import hilog from '@ohos.hilog'
679
680class Test {
681  onCreate() {
682    hilog.info(0x0000, 'testTag', '%{public}s', 'Application onCreate');
683  }
684  onDestroy() {
685    hilog.info(0x0000, 'testTag', '%{public}s', 'Application onDestroy');
686  }
687}
688
689export default new Test()
690```
691
692### 通过导入namespace获取类型
693
694**应用代码**
695
696```typescript
697import { BusinessError } from '@ohos.base';
698import bluetooth from '@ohos.bluetooth';
699let serverNumber = -1;
700function serverSocket(code: BusinessError, num: number) {
701  console.log('bluetooth error code: ' + code.code);
702  if (code.code == 0) {
703    console.log('bluetooth serverSocket Number: ' + num);
704    serverNumber = num;
705  }
706}
707
708let sppOption = { uuid: '', secure: false, type: 0 };
709bluetooth.sppListen('', sppOption, serverSocket);
710```
711
712**建议改法**
713
714```typescript
715import { BusinessError } from '@ohos.base';
716import bluetooth from '@ohos.bluetooth';
717let serverNumber = -1;
718function serverSocket(code: BusinessError, num: number) {
719  console.log('bluetooth error code: ' + code.code);
720  if (code.code == 0) {
721    console.log('bluetooth serverSocket Number: ' + num);
722    serverNumber = num;
723  }
724}
725
726let sppOption: bluetooth.SppOption = { uuid: '', secure: false, type: 0 };
727bluetooth.sppListen('', sppOption, serverSocket);
728```
729
730**原因**
731
732对象字面量缺少类型,根据`bluetooth.sppListen`分析可以得知,`sppOption`的类型来源于SDK,那么只需要将类型导入即可。
733注意到在`@ohos.bluetooth`中,`sppOption`是定义在namespace中的,所以在ets文件中,先导入namespace,再通过名称获取相应的类型。
734
735### object literal传参给Object类型
736
737**应用代码**
738
739```typescript
740function emit(event: string, ...args: Object[]): void {}
741
742emit('', {
743  'action': 11,
744  'outers': false
745});
746```
747
748**建议改法**
749
750```typescript
751function emit(event: string, ...args: Object[]): void {}
752
753let emitArg: Record<string, number | boolean> = {
754   'action': 11,
755   'outers': false
756}
757
758emit('', emitArg);
759```
760
761## arkts-no-obj-literals-as-types
762
763**应用代码**
764
765```typescript
766type Person = { name: string, age: number }
767```
768
769**建议改法**
770
771```typescript
772interface Person {
773  name: string,
774  age: number
775}
776```
777
778## arkts-no-noninferrable-arr-literals
779
780**应用代码**
781
782```typescript
783let permissionList = [
784  { name: '设备信息', value: '用于分析设备的续航、通话、上网、SIM卡故障等' },
785  { name: '麦克风', value: '用于反馈问题单时增加语音' },
786  { name: '存储', value: '用于反馈问题单时增加本地文件附件' }
787]
788```
789
790**建议改法**
791
792为对象字面量声明类型
793
794```typescript
795class PermissionItem {
796  name?: string
797  value?: string
798}
799
800let permissionList: PermissionItem[] = [
801  { name: '设备信息', value: '用于分析设备的续航、通话、上网、SIM卡故障等' },
802  { name: '麦克风', value: '用于反馈问题单时增加语音' },
803  { name: '存储', value: '用于反馈问题单时增加本地文件附件' }
804]
805```
806
807## arkts-no-method-reassignment
808
809**应用代码**
810
811```typescript
812class C {
813  add(left: number, right: number): number {
814    return left + right;
815  }
816}
817
818function sub(left: number, right: number): number {
819  return left - right;
820}
821
822let c1 = new C();
823c1.add = sub;
824```
825
826**建议改法**
827
828```typescript
829class C {
830  add: (left: number, right: number) => number =
831    (left: number, right: number) => {
832      return left + right;
833    }
834}
835
836function sub(left: number, right: number): number {
837  return left - right;
838}
839
840let c1 = new C();
841c1.add = sub;
842```
843
844## arkts-no-polymorphic-unops
845
846**应用代码**
847
848```typescript
849let a = +'5';
850let b = -'5';
851let c = ~'5';
852let d = +'string';
853```
854
855**建议改法**
856
857```typescript
858let a = Number.parseInt('5');
859let b = -Number.parseInt('5');
860let c = ~Number.parseInt('5');
861let d = new Number('string');
862```
863
864## arkts-no-type-query
865
866**应用代码**
867
868```typescript
869// module1.ts
870class C {
871  value: number = 0
872}
873
874export let c = new C()
875
876// module2.ts
877import { c } from './module1'
878let t: typeof c = { value: 123 };
879```
880
881**建议改法**
882
883```typescript
884// module1.ts
885class C {
886  value: number = 0
887}
888
889export { C }
890
891// module2.ts
892import { C } from './module1'
893let t: C = { value: 123 };
894```
895
896## arkts-no-in
897
898### 使用Object.keys判断属性是否存在
899
900**应用代码**
901
902```typescript
903function test(str: string, obj: Record<string, Object>) {
904  return str in obj;
905}
906```
907
908**建议改法**
909
910```typescript
911function test(str: string, obj: Record<string, Object>) {
912  for (let i of Object.keys(obj)) {
913    if (i == str) {
914      return true;
915    }
916  }
917  return false;
918}
919```
920
921## arkts-no-destruct-assignment
922
923**应用代码**
924
925```typescript
926let map = new Map<string, string>([['a', 'a'], ['b', 'b']]);
927for (let [key, value] of map) {
928  console.log(key);
929  console.log(value);
930}
931```
932
933**建议改法**
934
935使用数组
936
937```typescript
938let map = new Map<string, string>([['a', 'a'], ['b', 'b']]);
939for (let arr of map) {
940  let key = arr[0];
941  let value = arr[1];
942  console.log(key);
943  console.log(value);
944}
945```
946
947## arkts-no-types-in-catch
948
949**应用代码**
950
951```typescript
952import { BusinessError } from '@ohos.base';
953
954try {
955  // ...
956} catch (e: BusinessError) {
957  logger.error(e.code, e.message);
958}
959```
960
961**建议改法**
962
963```typescript
964import { BusinessError } from '@ohos.base';
965
966try {
967  // ...
968} catch (error) {
969  let e: BusinessError = error as BusinessError;
970  logger.error(e.code, e.message);
971}
972```
973
974## arkts-no-for-in
975
976**应用代码**
977
978```typescript
979interface Person {
980  [name: string]: string
981}
982let p: Person = {
983  name: 'tom',
984  age: '18'
985};
986
987for (let t in p) {
988  console.log(p[t]);
989}
990```
991
992**建议改法**
993
994```typescript
995let p: Record<string, string> = {
996  'name': 'tom',
997  'age': '18'
998};
999
1000for (let ele of Object.entries(p)) {
1001  console.log(ele[1]);
1002}
1003```
1004
1005## arkts-no-mapped-types
1006
1007**应用代码**
1008
1009```typescript
1010class C {
1011  a: number = 0
1012  b: number = 0
1013  c: number = 0
1014}
1015type OptionsFlags = {
1016  [Property in keyof C]: string
1017}
1018```
1019
1020**建议改法**
1021
1022```typescript
1023class C {
1024  a: number = 0
1025  b: number = 0
1026  c: number = 0
1027}
1028
1029type OptionsFlags = Record<keyof C, string>
1030```
1031
1032## arkts-limited-throw
1033
1034**应用代码**
1035
1036```typescript
1037import { BusinessError } from '@ohos.base';
1038
1039function ThrowError(error: BusinessError) {
1040  throw error;
1041}
1042```
1043
1044**建议改法**
1045
1046```typescript
1047import { BusinessError } from '@ohos.base';
1048
1049function ThrowError(error: BusinessError) {
1050  throw error as Error;
1051}
1052```
1053
1054**原因**
1055
1056`throw`语句中值的类型必须为`Error`或者其继承类,如果继承类是一个泛型,会有编译期报错。建议使用`as`将类型转换为`Error`。
1057
1058## arkts-no-standalone-this
1059
1060### 函数内使用this
1061
1062**应用代码**
1063
1064```typescript
1065function foo() {
1066  console.log(this.value);
1067}
1068
1069let obj = { value: 'abc' };
1070foo.apply(obj);
1071```
1072
1073**建议改法1**
1074
1075使用类的方法实现,如果该方法被多个类使用,可以考虑采用继承的机制
1076
1077```typescript
1078class Test {
1079  value: string = ''
1080  constructor (value: string) {
1081    this.value = value
1082  }
1083
1084  foo() {
1085    console.log(this.value);
1086  }
1087}
1088
1089let obj: Test = new Test('abc');
1090obj.foo();
1091```
1092
1093**建议改法2**
1094
1095将this作为参数传入
1096
1097```typescript
1098function foo(obj: Test) {
1099  console.log(obj.value);
1100}
1101
1102class Test {
1103  value: string = ''
1104}
1105
1106let obj: Test = { value: 'abc' };
1107foo(obj);
1108```
1109
1110**建议改法3**
1111
1112将属性作为参数传入
1113```typescript
1114function foo(value: string) {
1115  console.log(value);
1116}
1117
1118class Test {
1119  value: string = ''
1120}
1121
1122let obj: Test = { value: 'abc' };
1123foo(obj.value);
1124```
1125
1126### class的静态方法内使用this
1127
1128**应用代码**
1129
1130```typescript
1131class Test {
1132  static value: number = 123
1133  static foo(): number {
1134    return this.value
1135  }
1136}
1137```
1138
1139**建议改法**
1140
1141```typescript
1142class Test {
1143  static value: number = 123
1144  static foo(): number {
1145    return Test.value
1146  }
1147}
1148```
1149
1150## arkts-no-spread
1151
1152**应用代码**
1153
1154```typescript
1155import notification from '@ohos.notificationManager';
1156
1157function buildNotifyLongRequest(): notification.NotificationRequest {
1158  // ...
1159}
1160
1161let notificationRequest: notification.NotificationRequest = {
1162  ...buildNotifyLongRequest(),
1163  deliveryTime: new Date().getTime()
1164}
1165```
1166
1167**建议改法**
1168
1169```typescript
1170import notification from '@ohos.notificationManager';
1171
1172function buildNotifyLongRequest():notification.NotificationRequest {
1173    // ...
1174}
1175
1176let notificationRequest: notification.NotificationRequest = buildNotifyLongRequest();
1177notificationRequest.deliveryTime = new Date().getTime();
1178```
1179
1180**原因**
1181
1182ArkTS中,对象布局在编译期是确定的。如果需要将一个对象的所有属性展开赋值给另一个对象可以通过逐个属性赋值语句完成。在本例中,需要展开的对象和赋值的目标对象类型恰好相同,可以通过改变该对象属性的方式重构代码。
1183
1184## arkts-no-ctor-signatures-funcs
1185
1186在class内声明属性,而不是在构造函数上。
1187
1188**应用代码**
1189
1190```typescript
1191class Controller {
1192  value: string = ''
1193  constructor(value: string) {
1194    this.value = value
1195  }
1196}
1197
1198type ControllerConstructor = new (value: string) => Controller;
1199
1200class Menu {
1201  controller: ControllerConstructor = Controller
1202  createController() {
1203    if (this.controller) {
1204      return new this.controller('abc');
1205    }
1206    return null;
1207  }
1208}
1209
1210let t = new Menu()
1211console.log(t.createController()!.value)
1212```
1213
1214**建议改法**
1215
1216```typescript
1217class Controller {
1218  value: string = ''
1219  constructor(value: string) {
1220    this.value = value;
1221  }
1222}
1223
1224type ControllerConstructor = () => Controller;
1225
1226class Menu {
1227  controller: ControllerConstructor = () => { return new Controller('abc') }
1228  createController() {
1229    if (this.controller) {
1230      return this.controller();
1231    }
1232    return null;
1233  }
1234}
1235
1236let t: Menu = new Menu();
1237console.log(t.createController()!.value);
1238```
1239
1240## arkts-no-globalthis
1241
1242由于无法为globalThis添加静态类型,只能通过查找的方式访问globalThis的属性,造成额外的性能开销。另外,无法为globalThis的属性标记类型,无法保证对这些属性操作的安全和高性能。因此ArkTS不支持globalThis。
1243
12441. 建议按照业务逻辑根据`import/export`语法实现数据在不同模块的传递。
1245
12462. 必要情况下,可以通过构造的**单例对象**来实现全局对象的功能。(**说明:**不能在har中定义单例对象,har在打包时会在不同的hap中打包两份,无法实现单例。)
1247
1248**构造单例对象**
1249
1250```typescript
1251// 构造单例对象
1252export class GlobalContext {
1253  private constructor() {}
1254  private static instance: GlobalContext;
1255  private _objects = new Map<string, Object>();
1256
1257  public static getContext(): GlobalContext {
1258    if (!GlobalContext.instance) {
1259      GlobalContext.instance = new GlobalContext();
1260    }
1261    return GlobalContext.instance;
1262  }
1263
1264  getObject(value: string): Object | undefined {
1265    return this._objects.get(value);
1266  }
1267
1268  setObject(key: string, objectClass: Object): void {
1269    this._objects.set(key, objectClass);
1270  }
1271}
1272
1273```
1274
1275**应用代码**
1276
1277```typescript
1278
1279// file1.ts
1280
1281export class Test {
1282  value: string = '';
1283  foo(): void {
1284    globalThis.value = this.value;
1285  }
1286}
1287
1288// file2.ts
1289
1290globalThis.value;
1291
1292```
1293
1294**建议改法**
1295
1296```typescript
1297
1298// file1.ts
1299
1300import { GlobalContext } from '../GlobalContext'
1301
1302export class Test {
1303  value: string = '';
1304  foo(): void {
1305    GlobalContext.getContext().setObject('value', this.value);
1306  }
1307}
1308
1309// file2.ts
1310
1311import { GlobalContext } from '../GlobalContext'
1312
1313GlobalContext.getContext().getObject('value');
1314```
1315
1316## arkts-no-func-apply-bind-call
1317
1318### 使用标准库中接口
1319
1320**应用代码**
1321
1322```typescript
1323let arr: number[] = [1, 2, 3, 4];
1324let str = String.fromCharCode.apply(null, Array.from(arr));
1325```
1326
1327**建议改法**
1328
1329```typescript
1330let arr: number[] = [1, 2, 3, 4];
1331let str = String.fromCharCode(...Array.from(arr));
1332```
1333
1334### bind定义方法
1335
1336**应用代码**
1337
1338```typescript
1339class A {
1340  value: string = ''
1341  foo: Function = () => {}
1342}
1343
1344class Test {
1345  value: string = '1234'
1346  obj: A = {
1347    value: this.value,
1348    foo: this.foo.bind(this)
1349  }
1350
1351  foo() {
1352    console.log(this.value);
1353  }
1354}
1355```
1356
1357**建议改法1**
1358
1359```typescript
1360class A {
1361  value: string = ''
1362  foo: Function = () => {}
1363}
1364
1365class Test {
1366  value: string = '1234'
1367  obj: A = {
1368    value: this.value,
1369    foo: (): void => this.foo()
1370  }
1371
1372  foo() {
1373    console.log(this.value);
1374  }
1375}
1376```
1377
1378**建议改法2**
1379
1380```typescript
1381class A {
1382  value: string = ''
1383  foo: Function = () => {}
1384}
1385
1386class Test {
1387  value: string = '1234'
1388  foo: () => void = () => {
1389    console.log(this.value);
1390  }
1391  obj: A = {
1392    value: this.value,
1393    foo: this.foo
1394  }
1395}
1396```
1397
1398### 使用apply
1399
1400**应用代码**
1401
1402```typescript
1403class A {
1404  value: string;
1405  constructor (value: string) {
1406    this.value = value;
1407  }
1408
1409  foo() {
1410    console.log(this.value);
1411  }
1412}
1413
1414let a1 = new A('1');
1415let a2 = new A('2');
1416
1417a1.foo();
1418a1.foo.apply(a2);
1419```
1420
1421**建议改法**
1422
1423```typescript
1424class A {
1425  value: string;
1426  constructor (value: string) {
1427    this.value = value;
1428  }
1429
1430  foo() {
1431    this.fooApply(this);
1432  }
1433
1434  fooApply(a: A) {
1435    console.log(a.value);
1436  }
1437}
1438
1439let a1 = new A('1');
1440let a2 = new A('2');
1441
1442a1.foo();
1443a1.fooApply(a2);
1444```
1445
1446## arkts-limited-stdlib
1447
1448### `Object.fromEntries()`
1449
1450**应用代码**
1451
1452```typescript
1453let entries = new Map([
1454  ['foo', 123],
1455  ['bar', 456]
1456]);
1457
1458let obj = Object.fromEntries(entries);
1459```
1460
1461**建议改法**
1462
1463```typescript
1464let entries = new Map([
1465  ['foo', 123],
1466  ['bar', 456]
1467]);
1468
1469let obj: Record<string, Object> = {};
1470entries.forEach((value, key) => {
1471  if (key != undefined && key != null) {
1472    obj[key] = value;
1473  }
1474})
1475```
1476
1477### 使用`Number`的属性和方法
1478
1479ArkTS不允许使用全局对象的属性和方法: `Infinity, NaN, isFinite, isNaN, parseFloat, parseInt`
1480
1481可以使用`Number`的属性和方法: `Infinity, NaN, isFinite, isNaN, parseFloat, parseInt`
1482
1483**应用代码**
1484
1485```typescript
1486NaN;
1487isFinite(123);
1488parseInt('123');
1489```
1490
1491**建议改法**
1492
1493```typescript
1494Number.NaN;
1495Number.isFinite(123);
1496Number.parseInt('123');
1497```
1498
1499## arkts-strict-typing(StrictModeError)
1500
1501### strictPropertyInitialization
1502
1503**应用代码**
1504
1505```typescript
1506interface I {
1507  name:string
1508}
1509
1510class A {}
1511
1512class Test {
1513  a: number;
1514  b: string;
1515  c: boolean;
1516  d: I;
1517  e: A;
1518}
1519
1520```
1521
1522**建议改法**
1523
1524```typescript
1525interface I {
1526  name:string
1527}
1528
1529class A {}
1530
1531class Test {
1532  a: number;
1533  b: string;
1534  c: boolean;
1535  d: I = { name:'abc' };
1536  e: A | null = null;
1537  constructor(a:number, b:string, c:boolean) {
1538    this.a = a;
1539    this.b = b;
1540    this.c = c;
1541  }
1542}
1543
1544```
1545### Type `*** | null` is not assignable to type `***`
1546
1547**应用代码**
1548
1549```typescript
1550class A {
1551  bar() {}
1552}
1553function foo(n: number) {
1554  if (n === 0) {
1555    return null;
1556  }
1557  return new A();
1558}
1559function getNumber() {
1560  return 5;
1561}
1562let a:A = foo(getNumber());
1563a.bar();
1564```
1565
1566**建议改法**
1567
1568```typescript
1569class A {
1570  bar() {}
1571}
1572function foo(n: number) {
1573  if (n === 0) {
1574    return null;
1575  }
1576  return new A();
1577}
1578function getNumber() {
1579  return 5;
1580}
1581
1582let a: A | null = foo(getNumber());
1583a?.bar();
1584```
1585
1586### 严格属性初始化检查
1587
1588在class中,如果一个属性没有初始化,且没有在构造函数中被赋值,那么ArkTS将报错。
1589
1590**建议改法**
1591
15921.一般情况下,**建议按照业务逻辑**在声明时初始化属性,或者在构造函数中为属性赋值。如:
1593
1594```typescript
1595//code with error
1596class Test {
1597  value: number
1598  flag: boolean
1599}
1600
1601//方式一,在声明时初始化
1602class Test {
1603  value: number = 0
1604  flag: boolean = false
1605}
1606
1607//方式二,在构造函数中赋值
1608class Test {
1609  value: number
1610  flag: boolean
1611  constructor(value: number, flag: boolean) {
1612    this.value = value;
1613    this.flag = flag;
1614  }
1615}
1616```
1617
16182.对于对象类型(包括函数类型)`A`,如果不确定如何初始化,建议按照以下方式之一进行初始化
1619
1620​	方式(i)  `prop: A | null = null`
1621
1622​	方式(ii) `prop?: A`
1623
1624​	方式三(iii) `prop: A | undefined = undefined`
1625
1626- 从性能角度来说,`null`类型只用在编译期的类型检查中,对虚拟机的性能无影响。而`undefined | A`被视为联合类型,运行时可能有额外的开销。
1627- 从代码可读性、简洁性的角度来说,`prop?:A`是`prop: A | undefined = undefined`的语法糖,**推荐使用可选属性的写法**
1628
1629### 严格函数类型检查
1630
1631**应用代码**
1632
1633```typescript
1634function foo(fn: (value?: string) => void, value: string): void {}
1635
1636foo((value: string) => {}, ''); //error
1637```
1638
1639**建议改法**
1640
1641```typescript
1642function foo(fn: (value?: string) => void, value: string): void {}
1643
1644foo((value?: string) => {}, '');
1645```
1646
1647**原因**
1648
1649例如,在以下的例子中,如果编译期不开启严格函数类型的检查,那么该段代码可以编译通过,但是在运行时会产生非预期的行为。具体来看,在`foo`的函数体中,一个`undefined`被传入`fn`(这是可以的,因为`fn`可以接受`undefined`),但是在代码第6行`foo`的调用点,传入的`(value: string) => { console.log(value.toUpperCase()) }`的函数实现中,始终将参数`value`当做string类型,允许其调用`toUpperCase`方法。如果不开启严格函数类型的检查,那么这段代码在运行时,会出现在`undefined`上无法找到属性的错误。
1650
1651```typescript
1652function foo(fn: (value?: string) => void, value: string): void {
1653  let v: string | undefined = undefined;
1654  fn(v);
1655}
1656
1657foo((value: string) => { console.log(value.toUpperCase()) }, ''); // Cannot read properties of undefined (reading 'toUpperCase')
1658```
1659
1660为了避免运行时的非预期行为,如果在编译时开启了严格类型检查,这段代码将编译不通过,从而可以提醒开发者修改代码,保证程序安全。
1661
1662### 严格空值检查
1663
1664**应用代码**
1665
1666```typescript
1667class Test {
1668  private value?: string
1669
1670  public printValue () {
1671    console.log(this.value.toLowerCase());
1672  }
1673}
1674
1675let t = new Test();
1676t.printValue();
1677```
1678
1679**建议改法**
1680
1681在编写代码时,建议减少可空类型的使用。如果对变量、属性标记了可空类型,那么在使用它们之间,需要进行空值的判断,根据是否为空值处理不同的逻辑。
1682
1683```typescript
1684class Test {
1685  private value?: string
1686
1687  public printValue () {
1688    if (this.value) {
1689      console.log(this.value.toLowerCase());
1690    }
1691  }
1692}
1693
1694let t = new Test();
1695t.printValue();
1696```
1697
1698**原因**
1699
1700在第一段代码中,如果编译期不开启严格空值检查,那么该段代码可以编译通过,但是在运行时会产生非预期的行为。这是因为`t`的属性`value`为`undefined`(这是因为`value?: string`是`value: string | undefined = undefined`的语法糖),在第11行调用`printValue`方法时,由于在该方法体内未对`this.value`的值进行空值检查,而直接按照`string`类型访问其属性,这就导致了运行时的错误。为了避免运行时的非预期行为,如果在编译时开起来严格空值检查,这段代码将编译不通过从而可以提醒开发者修改代码(如按照第二段代码的方式),保证程序安全。
1701
1702### 函数返回类型不匹配
1703
1704**应用代码**
1705
1706```typescript
1707class Test {
1708  handleClick: (action: string, externInfo?: string) => void | null = null;
1709}
1710```
1711
1712**建议改法**
1713
1714在这种写法下,函数返回类型被解析为 `void | undefined`,需要添加括号用来区分union类型。
1715
1716```typescript
1717class Test {
1718  handleClick: ((action: string, externInfo?: string) => void) | null = null;
1719}
1720```
1721
1722### '***' is of type 'unknown'
1723
1724**应用代码**
1725
1726```typescript
1727try {
1728
1729} catch (error) {
1730  console.log(error.message);
1731}
1732```
1733
1734**建议改法**
1735
1736```typescript
1737import { BusinessError } from '@ohos.base'
1738
1739try {
1740
1741} catch (error) {
1742  console.log((error as BusinessError).message);
1743}
1744```
1745
1746### Type '*** | null' is not assignable to type '\*\*\*'
1747
1748**应用代码**
1749
1750```typescript
1751class A {
1752  value: number
1753  constructor(value: number) {
1754    this.value = value;
1755  }
1756}
1757
1758function foo(v: number): A | null {
1759  if (v > 0) {
1760    return new A(v);
1761  }
1762  return null;
1763}
1764
1765let a: A = foo();
1766```
1767
1768**建议改法1**
1769
1770修改变量`a`的类型:`let a: A | null = foo()`。
1771
1772```typescript
1773class A {
1774  value: number
1775  constructor(value: number) {
1776    this.value = value;
1777  }
1778}
1779
1780function foo(v: number): A | null {
1781  if (v > 0) {
1782    return new A(v);
1783  }
1784  return null;
1785}
1786
1787let a: A | null = foo(123);
1788
1789if (a != null) {
1790  // 非空分支
1791} else {
1792  // 处理null
1793}
1794```
1795
1796**建议改法2**
1797
1798如果可以断定此处调用`foo`一定返回非空值,可以使用非空断言`!`。
1799
1800```typescript
1801class A {
1802  value: number
1803  constructor(value: number) {
1804    this.value = value;
1805  }
1806}
1807
1808function foo(v: number): A | null {
1809  if (v > 0) {
1810    return new A(v);
1811  }
1812  return null;
1813}
1814
1815let a: A = foo(123)!;
1816```
1817
1818### Cannot invoke an object which possibly 'undefined'
1819
1820**应用代码**
1821
1822```typescript
1823interface A {
1824  foo?: () => void
1825}
1826
1827let a:A = { foo: () => {} };
1828a.foo();
1829```
1830
1831**建议改法1**
1832
1833```typescript
1834interface A {
1835  foo: () => void
1836}
1837let a: A = { foo: () => {} };
1838a.foo();
1839```
1840
1841**建议改法2**
1842
1843```typescript
1844interface A {
1845  foo?: () => void
1846}
1847
1848let a: A = { foo: () => {} };
1849if (a.foo) {
1850  a.foo();
1851}
1852```
1853
1854**原因**
1855
1856在原先代码的定义中,foo是可选属性,有可能为undefined,对undefined的调用会导致报错。建议按照业务逻辑判断是否需要为可选属性。如果确实需要,那么在访问到该属性后需要进行空值检查。
1857
1858### Variable '***' is used before being assigned
1859
1860**应用代码**
1861
1862```typescript
1863class Test {
1864  value: number = 0
1865}
1866
1867let a: Test
1868try {
1869  a = { value: 1};
1870} catch (e) {
1871  a.value;
1872}
1873a.value;
1874```
1875
1876**建议改法**
1877
1878```typescript
1879class Test {
1880  value: number = 0
1881}
1882
1883let a: Test | null = null;
1884try {
1885  a = { value:1 };
1886} catch (e) {
1887  if (a) {
1888    a.value;
1889  }
1890}
1891
1892if (a) {
1893  a.value;
1894}
1895```
1896
1897**原因**
1898
1899对于primitive types,可以根据业务逻辑赋值,例如0,'',false。
1900
1901对于对象类型,可以将类型修改为和null的联合类型,并赋值null,使用时需要进行非空检查。
1902
1903### Function lacks ending return statement and return type does not include 'undefined'.
1904
1905**应用代码**
1906
1907```typescript
1908function foo(a: number): number {
1909  if (a > 0) {
1910    return a;
1911  }
1912}
1913```
1914
1915**建议改法1**
1916
1917根据业务逻辑,在else分支中返回合适的数值
1918
1919**建议改法2**
1920
1921```typescript
1922function foo(a: number): number | undefined {
1923  if (a > 0) {
1924    return a;
1925  }
1926  return
1927}
1928```
1929
1930## arkts-strict-typing-required
1931
1932**应用代码**
1933
1934```typescript
1935// @ts-nocheck
1936var a: any = 123;
1937```
1938
1939**建议改法**
1940
1941```typescript
1942let a: number = 123;
1943```
1944
1945**原因**
1946
1947ArkTS不支持通过注释的方式绕过严格类型检查。首先将注释(`// @ts-nocheck`或者`// @ts-ignore`)删去,再根据报错信息修改其他代码。
1948
1949## Importing ArkTS files to JS and TS files is not allowed
1950
1951## arkts-no-tsdeps
1952
1953不允许.ts、.js文件`import`.ets文件源码。
1954
1955**建议改法**
1956
1957方式1.将.ts文件的后缀修改成ets,按照ArkTS语法规则适配代码。
1958
1959方式2.将.ets文件中被.ts文件依赖的代码单独抽取到.ts文件中。
1960
1961## arkts-no-special-imports
1962
1963**应用代码**
1964
1965```typescript
1966import type {A, B, C, D } from '***'
1967```
1968
1969
1970**建议改法**
1971
1972```typescript
1973import {A, B, C, D } from '***'
1974```
1975
1976## arkts-no-classes-as-obj
1977
1978### 使用class构造实例
1979
1980**应用代码**
1981
1982```typescript
1983class Controller {
1984  value: string = ''
1985  constructor(value: string) {
1986    this.value = value
1987  }
1988}
1989
1990interface ControllerConstructor {
1991  new (value: string): Controller;
1992}
1993
1994class Menu {
1995  controller: ControllerConstructor = Controller
1996  createController() {
1997    if (this.controller) {
1998      return new this.controller('abc');
1999    }
2000    return null;
2001  }
2002}
2003
2004let t = new Menu();
2005console.log(t.createController()!.value);
2006```
2007
2008**建议改法**
2009
2010```typescript
2011class Controller {
2012  value: string = ''
2013  constructor(value: string) {
2014    this.value = value
2015  }
2016}
2017
2018type ControllerConstructor = () => Controller;
2019
2020class Menu {
2021  controller: ControllerConstructor = () => { return new Controller('abc'); }
2022  createController() {
2023    if (this.controller) {
2024      return this.controller();
2025    }
2026    return null;
2027  }
2028}
2029
2030let t: Menu = new Menu();
2031console.log(t.createController()!.value);
2032```
2033
2034### 访问静态属性
2035
2036**应用代码**
2037
2038```typescript
2039class C1 {
2040  static value: string = 'abc'
2041}
2042
2043class C2 {
2044  static value: string = 'def'
2045}
2046
2047function getValue(obj: any) {
2048  return obj['value'];
2049}
2050
2051console.log(getValue(C1));
2052console.log(getValue(C2));
2053```
2054
2055**建议改法**
2056
2057```typescript
2058class C1 {
2059  static value: string = 'abc'
2060}
2061
2062class C2 {
2063  static value: string = 'def'
2064}
2065
2066function getC1Value(): string {
2067  return C1.value;
2068}
2069
2070function getC2Value(): string {
2071  return C2.value;
2072}
2073
2074console.log(getC1Value());
2075console.log(getC2Value());
2076```
2077
2078## arkts-no-side-effects-imports
2079
2080改用动态import
2081
2082**应用代码**
2083
2084```typescript
2085import 'module'
2086```
2087
2088**建议改法**
2089
2090```typescript
2091import('module')
2092```
2093
2094## arkts-no-func-props
2095
2096**应用代码**
2097
2098```typescript
2099function foo(value: number): void {
2100  console.log(value.toString());
2101}
2102
2103foo.add = (left: number, right: number) => {
2104  return left + right;
2105}
2106
2107foo.sub = (left: number, right: number) => {
2108  return left - right;
2109}
2110```
2111
2112**建议改法**
2113
2114```typescript
2115class Foo {
2116  static foo(value: number): void {
2117    console.log(value.toString());
2118  }
2119
2120  static add(left: number, right: number): number {
2121    return left + right;
2122  }
2123
2124  static sub(left: number, right: number): number {
2125    return left - right;
2126  }
2127}
2128```
2129
2130## 状态管理使用典型场景
2131
2132### Struct组件外使用状态变量
2133
2134由于struct和class不同,不建议把this作为参数传递到struct外部使用,避免引起实例引用无法释放的情况,导致内存泄露。建议将状态变量对象传递到struct外面使用,通过修改对象的属性,来触发UI刷新。
2135
2136**不推荐用法**
2137
2138```typescript
2139export class MyComponentController {
2140  item: MyComponent = null;
2141
2142  setItem(item: MyComponent) {
2143    this.item = item;
2144  }
2145
2146  changeText(value: string) {
2147    this.item.value = value;
2148  }
2149}
2150
2151@Component
2152export default struct MyComponent {
2153  public controller: MyComponentController = null;
2154  @State value: string = 'Hello World';
2155
2156  build() {
2157    Column() {
2158      Text(this.value)
2159        .fontSize(50)
2160    }
2161  }
2162
2163  aboutToAppear() {
2164    if (this.controller)
2165      this.controller.setItem(this);
2166  }
2167}
2168
2169@Entry
2170@Component
2171struct ObjThisOldPage {
2172  controller = new MyComponentController();
2173
2174  build() {
2175    Column() {
2176      MyComponent({ controller: this.controller })
2177      Button('change value').onClick(() => {
2178        this.controller.changeText('Text');
2179      })
2180    }
2181  }
2182}
2183```
2184
2185**推荐用法**
2186
2187```typescript
2188class CC {
2189  value: string = '1';
2190
2191  constructor(value: string) {
2192    this.value = value;
2193  }
2194}
2195
2196export class MyComponentController {
2197  item: CC = new CC('1');
2198
2199  setItem(item: CC) {
2200    this.item = item;
2201  }
2202
2203  changeText(value: string) {
2204    this.item.value = value;
2205  }
2206}
2207
2208@Component
2209export default struct MyComponent {
2210  public controller: MyComponentController | null = null;
2211  @State value: CC = new CC('Hello World')
2212
2213  build() {
2214    Column() {
2215      Text(`${this.value.value}`)
2216        .fontSize(50)
2217    }
2218  }
2219
2220  aboutToAppear() {
2221    if (this.controller)
2222      this.controller.setItem(this.value);
2223  }
2224}
2225
2226@Entry
2227@Component
2228struct StyleExample {
2229  controller: MyComponentController = new MyComponentController();
2230
2231  build() {
2232    Column() {
2233      MyComponent({ controller: this.controller })
2234      Button('change value').onClick(() => {
2235        this.controller.changeText('Text')
2236      })
2237    }
2238  }
2239}
2240```
2241
2242### Struct支持联合类型的方案
2243
2244下面这段代码有arkts-no-any-unknown的报错,由于strcut不支持泛型,建议使用联合类型,实现自定义组件类似泛型的功能。
2245
2246**不推荐用法**
2247
2248```typescript
2249class Data {
2250  aa: number = 11;
2251}
2252
2253@Entry
2254@Component
2255struct DatauionOldPage {
2256  @State array: Data[] = [new Data(), new Data(), new Data()];
2257
2258  @Builder
2259  componentCloser(data: Data) {
2260    Text(data.aa + '').fontSize(50)
2261  }
2262
2263  build() {
2264    Row() {
2265      Column() {
2266        ForEachCom({ arrayList: this.array, closer: this.componentCloser })
2267      }
2268      .width('100%')
2269    }
2270    .height('100%')
2271  }
2272}
2273
2274@Component
2275export struct ForEachCom {
2276  arrayList: any[]
2277  @BuilderParam closer: (data: any) => void = this.componentCloser
2278
2279  @Builder
2280  componentCloser() {
2281  }
2282
2283  build() {
2284    Column() {
2285      ForEach(this.arrayList, (item: any) => {
2286        Row() {
2287          this.closer(item)
2288        }.width('100%').height(200).backgroundColor('#eee')
2289      })
2290    }
2291  }
2292}
2293```
2294
2295**推荐用法**
2296
2297```typescript
2298class Data {
2299  aa: number = 11;
2300}
2301
2302class Model {
2303  aa: string = '11';
2304}
2305
2306type UnionData = Data | Model
2307
2308@Entry
2309@Component
2310struct DatauionPage {
2311  array: UnionData[] = [new Data(), new Data(), new Data()];
2312
2313  @Builder
2314  componentCloser(data: UnionData) {
2315    if (data instanceof Data) {
2316      Text(data.aa + '').fontSize(50)
2317    }
2318  }
2319
2320  build() {
2321    Row() {
2322      Column() {
2323        ForEachCom({ arrayList: this.array, closer: this.componentCloser })
2324      }
2325      .width('100%')
2326    }
2327    .height('100%')
2328  }
2329}
2330
2331@Component
2332export struct ForEachCom {
2333  arrayList: UnionData[] = [new Data(), new Data(), new Data()];
2334  @BuilderParam closer: (data: UnionData) => void = this.componentCloser
2335
2336  @Builder
2337  componentCloser() {
2338  }
2339
2340  build() {
2341    Column() {
2342      ForEach(this.arrayList, (item: UnionData) => {
2343        Row() {
2344          this.closer(item)
2345        }.width('100%').height(200).backgroundColor('#eee')
2346      })
2347    }
2348  }
2349}
2350```