• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# ArkTS Coding Style Guide
2
3<!--Kit: ArkTS-->
4<!--Subsystem: ArkCompiler-->
5<!--Owner: @yyytiancai-->
6<!--Designer: @qyhuo32-->
7<!--Tester: @kirl75; @zsw_zhushiwei-->
8<!--Adviser: @zhang_yixin13-->
9
10## Purpose
11
12Based on the language characteristics of ArkTS, as well as industry standards and practices, this guide provides coding guide for improving code standardization, security, and performance.
13
14This guide is applicable when you use ArkTS for coding during application development.
15
16## Source
17
18ArkTS further enhances static check and analysis while maintaining the basic syntax style of TypeScript. Some rules in this topic are selected from the [TypeScript and JavaScript Coding Style Guide](https://gitcode.com/openharmony/docs/blob/master/en/contribute/OpenHarmony-Application-Typescript-JavaScript-coding-guide.md), providing standards for ArkTS-specific syntax to improve code readability and execution performance.
19
20## Document Structure
21
22### Coding Style
23
24Style for the naming and format.
25
26### Programming Practices
27
28Practices for declaration, initialization, data types, operations and expressions, and exceptions.
29
30Guidelines in *TypeScript and JavaScript Coding Style Guide* that are involved in the ArkTS language are extracted, and new guidelines are added for ArkTS-specific syntax.
31
32## Terms
33
34|  Term  | Acronym/Abbreviation | Description|
35|  ----  | ----  |  ----|
36| ArkTS  | N/A| ArkTS programming language|
37| TypeScript  | TS | TypeScript programming language|
38| JavaScript  | JS | JavaScript programming language|
39| ESObject  | N/A| JS/TS object in ArkTS cross-language calls|
40
41## Principle
42
43Guidelines are categorized as follows:
44
45**Rule**: a convention that must be complied with. All contents in this document are for ArkTS.
46
47**Recommendation**: a convention that must be considered.
48
49## Naming
50
51### Properly Name Identifiers to Make Them Easy to Read
52
53**[Description]**
54
55A well-named identifier meets the following requirements:
56 - Clearly express the intent. Do not use single letters or non-standard abbreviations.
57 - Use correct English words in line with the English grammar. Do not use Pinyin.
58 - Ensure that the statement is clear and unambiguous.
59
60### Use UpperCamelCase for Class Names, Enum Names, and Namespace Names
61
62**[Category]** Recommendation
63
64**[Description]**
65
66Classes are named in upper camel case.
67Class names are usually nouns or noun phrases, for example, Person, Student, and Worker. Avoid verbs and ambiguous words like Data and Info in class names.
68
69**[Correct Example]**
70```
71// Class name
72class User {
73  username: string
74
75  constructor(username: string) {
76    this.username = username;
77  }
78
79  sayHi() {
80    console.log('hi' + this.username);
81  }
82}
83
84// Enum name
85enum UserType {
86  TEACHER = 0,
87  STUDENT = 1
88};
89
90// Namespace name
91namespace Base64Utils {
92  function encrypt() {
93    // todo encrypt
94  }
95
96  function decrypt() {
97    // todo decrypt
98  }
99};
100```
101
102### Use lowerCamelCase for Variable Names, Method Names, and Parameter Names
103
104**[Category]** Recommendation
105
106**[Description]**
107
108A function is usually named as a verb or verb phrase in lower camel case. Examples are as follows:
1091. load + attributeName()
1102. put + attributeName()
1113. is + BooleanAttributeName()
1124. has + noun/adjective()
1135. verb()
1146. verb + object()
115A variable name is usually a noun or noun phrase in lower camel case.
116
117**[Correct Example]**
118```
119let msg = 'Hello world';
120
121function sendMsg(msg: string) {
122  // todo send message
123}
124
125let userName = 'Zhangsan';
126
127function findUser(userName: string) {
128  // todo find user by user name
129}
130```
131
132### Use Uppercase Letters for Constant Names and Enum Value Names and Separate Words by Underscores
133
134**[Category]** Recommendation
135
136**[Description]**
137
138A constant name must consist of uppercase letters separated by underscores (_). A constant name should express complete semantics whenever possible.
139
140**[Correct Example]**
141
142```
143const MAX_USER_SIZE = 10000;
144
145enum UserType {
146  TEACHER = 0,
147  STUDENT = 1
148};
149```
150
151### Do Not Use Negative Boolean Variable Names
152
153**[Category]** Recommendation
154
155**[Description]**
156
157It is recommended that a local variable of the Boolean type be prefixed with a meaningless expression, for example, is, has, can, or should. It is confusing when a logical NOT operator is used in a double negative phrase, for example, !isNotError. Therefore, avoid defining negative Boolean variable names.
158
159**[Incorrect Example]**
160
161```
162let isNoError = true;
163let isNotFound = false;
164
165function empty() {}
166function next() {}
167```
168
169**[Correct Example]**
170
171```
172let isError = false;
173let isFound = true;
174
175function isEmpty() {}
176function hasNext() {}
177```
178
179## Format
180
181### Use Spaces for Indentation
182
183**[Category]** Recommendation
184
185**[Description]**
186
187Use spaces only to indent.
188
189Preferentially use two-space indentation in most scenarios. Use four spaces in line break scenarios.
190Do not use the Tab key to indent. Currently, almost all IDEs and code editors support automatic conversion of a Tab input to two spaces. The code editors should be configured to use spaces for indentation.
191
192**[Correct Example]**
193
194```
195class DataSource {
196  id: number = 0
197  title: string = ''
198  content: string = ''
199}
200
201const dataSource: DataSource[] = [
202  {
203    id: 1,
204    title: 'Title 1',
205    content: 'Content 1'
206  },
207  {
208    id: 2,
209    title: 'Title 2',
210    content: 'Content 2'
211  }
212
213];
214
215function test(dataSource: DataSource[]) {
216  if (!dataSource.length) {
217    return;
218  }
219
220  for (let data of dataSource) {
221    if (!data || !data.id || !data.title || !data.content) {
222      continue;
223    }
224    // some code
225  }
226
227  // some code
228}
229```
230
231### Use No More Than 120 Characters in Each Line
232
233**[Category]** Recommendation
234
235**[Description]**
236
237The code line width should not be too long. Otherwise, it is difficult to read.
238
239The line width requirement encourages you to shorten function and variable names, reduce nesting, and write concise comments to improve code readability.
240It is recommended that each line contain no more than 120 characters unless a longer line can significantly improve the code readability and no information is hidden.
241Exception: If a one-line comment contains a command or URL of more than 120 characters, you can keep the line for ease in using copy, paste, and search with the **grep** command. Put the error information of preprocessor directives in one line to facilitate reading and understanding even if the line contains more than 120 characters.
242
243### Use Braces in Conditional Statements and Loop Statements
244
245**[Category]** Recommendation
246
247**[Description]**
248
249It is a best practice to add braces ({}) to the execution body of statements such as **if**, **for**, **do**, and **while**, because omitting the braces may cause errors and reduce code clarity.
250
251**[Incorrect Example]**
252
253```
254if (condition)
255  console.log('success');
256
257for (let idx = 0; idx < 5; ++idx)
258  console.log(idx);
259```
260
261**[Correct Example]**
262
263```
264if (condition) {
265  console.log('success');
266}
267
268for (let idx = 0; idx < 5; ++idx) {
269  console.log(idx);
270}
271```
272
273### Indent case and default in the switch Statement Block
274
275**[Category]** Recommendation
276
277**[Description]**
278
279Use two spaces to indent the case or default statement in a switch statement block. Use two spaces to indent the line feed statement after the switch label.
280
281**[Correct Example]**
282
283```
284switch (condition) {
285  case 0: {
286    doSomething();
287    break;
288  }
289  case 1: {
290    doOtherthing();
291    break;
292  }
293  default:
294    break;
295}
296```
297
298### Keep a Consistent Line Break Style for Expressions
299
300**[Category]** Recommendation
301
302**[Description]**
303
304When a statement is too long or difficult to read, start a new line at a proper position.
305During line breaking, always place operators at the end of lines, indicating that the operations are to be continued. This is also the default configurations of typical formatting tools.
306
307**[Correct Example]**
308
309```
310// The if conditional statement exceeds the line width.
311if (userCount > MAX_USER_COUNT ||
312  userCount < MIN_USER_COUNT) {
313  doSomething();
314}
315```
316
317### Do Not Put Multiple Variable Definitions and Assignment Statements in a Line
318
319**[Category]** Rule
320
321**[Description]**
322
323Each statement should declare only one variable.
324In this way, it is easier to add variable declarations and can avoid errors, because you do not need to consider changing a semicolon (;) to a comma (,). It is also easier for the debugger to debug variables one by one, rather than skipping all variables at a time.
325
326**[Incorrect Example]**
327
328```
329let maxCount = 10, isCompleted = false;
330let pointX, pointY;
331pointX = 10; pointY = 0;
332```
333
334**[Correct Example]**
335
336```
337let maxCount = 10;
338let isCompleted = false;
339let pointX = 0;
340let pointY = 0;
341```
342
343### Use Spaces to Highlight Keywords and Important Information
344
345**[Category]** Recommendation
346
347**[Description]**
348
349Use spaces to highlight keywords and important information. The general recommendations are as follows:
3501. Add a space between keywords such as **if**, **for**, **while**, and **switch** and the open parentheses.
3512. Do not add a space between the method name and the open parentheses of the parameter list when defining or calling the method.
3523. Add a space between the keyword **else** or **catch** and the close brace (}).
3534. Add a space before the open brace ({), except when:
354a. The open brace is used as the first parameter of a method or the first element in an array, for example, **foo({ name: 'abc' })**.
355b. The open brace is used in a template name, for example, **abc${name}**.
3565. Spaces are added before and after the binary operator (+, -, *, =, <, >, <=, >=, ===, !==, &&, ||). Spaces are added on both sides of the ternary operator (? :).
3576. Add a space after the comma in array initialization and the comma between multiple parameters in a method.
3587. Do not add a space before a comma (,) or semicolon (;).
3598. Do not add spaces inside the square brackets ([]) of an array.
3609. Do not contain multiple consecutive spaces. It is a bad practice if consecutive spaces in a line are not used for indentation.
361
362**[Incorrect Example]**
363
364```
365// There is no space between if and the open parenthesis.
366if(isJedi) {
367  fight();
368}
369
370// There is a space between the method name fight and the open parenthesis.
371function fight (): void {
372  console.log('Swooosh!');
373}
374```
375
376**[Correct Example]**
377
378```
379// There is a space between if and the open parenthesis.
380if (isJedi) {
381  fight();
382}
383
384// There is no space between the method name fight and the open parenthesis.
385function fight(): void {
386  console.log('Swooosh!');
387}
388```
389
390**[Incorrect Example]**
391
392```
393if (flag) {
394  // ...
395}else {  // There is no space between the close brace and else.
396  // ...
397}
398```
399
400**[Correct Example]**
401
402```
403if (flag) {
404  // ...
405} else {  // There is a space between the close brace and else.
406  // ...
407}
408```
409
410**[Correct Example]**
411
412```
413function foo() {  // There is a space before the open brace in the method declaration.
414  // ...
415}
416
417bar('attr', {  // There is a space before the open brace.
418  age: '1 year',
419  sbreed: 'Bernese Mountain Dog',
420});
421```
422
423**[Correct Example]**
424
425```
426const arr = [1, 2, 3];  // There is a space after the comma during array initialization. There is no space before the comma.
427myFunc(bar, foo, baz);  // There is a space after the comma between multiple parameters of a method. There is no space before the comma.
428```
429
430### Use Single Quotation Marks for Strings
431
432**[Category]** Recommendation
433
434**[Description]**
435
436To maintain code consistency and readability, use single quotes.
437
438**[Incorrect Example]**
439
440```
441let message = "world";
442console.log(message);
443```
444
445**[Correct Example]**
446
447```
448let message = 'world';
449console.log(message);
450```
451
452### If an Object Literal Has More Than Four Properties, Place Each of Them at Separate Lines
453
454**[Category]** Recommendation
455
456**[Description]**
457
458The properties of an object literal should be all placed at the same line or each at a separate line. If an object literal has more than four properties, place each of them at separate lines.
459
460**[Incorrect Example]**
461
462```
463interface I {
464  name: string
465  age: number
466  value: number
467  sum: number
468  foo: boolean
469  bar: boolean
470}
471
472let obj: I = { name: 'tom', age: 16, value: 1, sum: 2, foo: true, bar: false }
473```
474
475**[Correct Example]**
476
477```
478interface I {
479  name: string
480  age: number
481  value: number
482  sum: number
483  foo: boolean
484  bar: boolean
485}
486
487let obj: I = {
488  name: 'tom',
489  age: 16,
490  value: 1,
491  sum: 2,
492  foo: true,
493  bar: false
494}
495```
496
497### Put else or catch in the Same Line as the Close Parenthesis of the if or try Code Block
498
499**[Category]** Recommendation
500
501**[Description]**
502
503In conditional statements, place **else** in the same line as the close parenthesis of the **if** code block. Similarly, in exception handling statements, place **catch** in the same line as the close parenthesis of the **try** code block.
504
505**[Incorrect Example]**
506
507```
508if (isOk) {
509  doThing1();
510  doThing2();
511}
512else {
513  doThing3();
514}
515```
516
517**[Correct Example]**
518
519```
520if (isOk) {
521  doThing1();
522  doThing2();
523} else {
524  doThing3();
525}
526```
527
528**[Incorrect Example]**
529
530```
531try {
532  doSomething();
533}
534catch (err) {
535  // Error handling.
536}
537```
538
539**[Correct Example]**
540
541```
542try {
543  doSomething();
544} catch (err) {
545  // Error handling.
546}
547```
548
549### Put the Open Brace and the Statement in the Same Line
550
551**[Category]** Recommendation
552
553**[Description]**
554
555Follow a consistent style of using braces in the project. You are advised to put the open brace ({) and the control or declaration statement in the same line.
556
557**[Incorrect Example]**
558
559```
560function foo()
561{
562  // ...
563}
564```
565
566**[Correct Example]**
567
568```
569function foo() {
570  // ...
571}
572```
573
574## Programming Practices
575
576### Add Accessible Modifiers for Class Properties
577
578**[Category]** Recommendation
579
580**[Description]**
581
582ArkTS provides the **private**, **protected**, and **public** access modifiers. The default accessible modifier of a property is **public**. Appropriate accessible modifiers can improve code security and readability. Note: If a class contains the **private** attribute, the class cannot be initialized through object literals.
583
584**[Incorrect Example]**
585
586```
587class C {
588  count: number = 0
589
590  getCount(): number {
591    return this.count
592  }
593}
594```
595
596**[Correct Example]**
597
598```
599class C {
600  private count: number = 0
601
602  public getCount(): number {
603    return this.count
604  }
605}
606```
607
608### Do Not Omit 0s Before and After the Decimal Point of a Floating-Point Number
609
610**[Category]** Recommendation
611
612**[Description]**
613
614In ArkTS, a floating-point number must contain a decimal point, but no digit is required before or after the decimal point. However, using digits before and after the decimal point can improve code readability.
615
616**[Incorrect Example]**
617
618```
619const num = .5;
620const num = 2.;
621const num = -.7;
622```
623
624**[Correct Example]**
625
626```
627const num = 0.5;
628const num = 2.0;
629const num = -0.7;
630```
631
632### Use Number.isNaN() to Check Whether a Variable Is Number.NaN
633
634**[Category]** Rule
635
636**[Description]**
637
638In ArkTS, **Number.NaN** is a particular value of a numeric data type. It represents a non-numeric value in the double-precision 64-bit format, as defined in the IEEE floating-point standard.
639**Number.NaN** is unique in ArkTS because it is not equal to any value, including itself. For example, the result of comparison with **Number.NaN** is confusing, as the values of **Number.NaN !== Number.NaN** and **Number.NaN != Number.NaN** are both **true**.
640Therefore, you must use **Number.isNaN()** to check whether a value is **Number.NaN**.
641
642**[Incorrect Example]**
643
644```
645if (foo == Number.NaN) {
646  // ...
647}
648
649if (foo != Number.NaN) {
650  // ...
651}
652```
653
654**[Correct Example]**
655
656```
657if (Number.isNaN(foo)) {
658  // ...
659}
660
661if (!Number.isNaN(foo)) {
662  // ...
663}
664```
665
666### Preferentially Use Array Object Methods for Array Traversal
667
668**[Category]** Rule
669
670**[Description]**
671
672To traverse an array, preferentially use the methods provided by **Array**, such as **forEach()**, **map()**, **every()**, **filter()**, **find()**, **findIndex()**, **reduce()**, and **some()**.
673
674**[Incorrect Example]**
675
676```
677const numbers = [1, 2, 3, 4, 5];
678// Use for to traverse an existing array to generate a new array.
679const increasedByOne: number[] = [];
680for (let i = 0; i < numbers.length; i++) {
681  increasedByOne.push(numbers[i] + 1);
682}
683```
684
685**[Correct Example]**
686
687```
688const numbers = [1, 2, 3, 4, 5];
689// Better: Use the map method.
690const increasedByOne: number[] = numbers.map(num => num + 1);
691```
692
693### Do Not Assign Values in Control Conditional Expressions
694
695**[Category]** Rule
696
697**[Description]**
698
699Control conditional expressions are usually used in **if**, **while**, **for**, and **?:** statements.
700Assigning values in this type of expression often leads to unexpected behavior and poor code readability.
701
702**[Incorrect Example]**
703
704```
705// It is difficult to understand the value assignment in the control conditional expression.
706if (isFoo = false) {
707  // ...
708}
709```
710
711**[Correct Example]**
712
713```
714const isFoo = false; // Assign a value above and directly use it in the if statement.
715if (isFoo) {
716  // ...
717}
718```
719
720### Do Not Use return, break, continue, or throw in a finally Code Block
721
722**[Category]** Rule
723
724**[Description]**
725
726If the **return**, **break**, **continue**, or **throw** statement is used in a **finally** code block or an exception that arises during method calling is not handled, the **finally** code block cannot properly stop. An abnormally stopped **finally** code block affects the throwing of exceptions in a **try** or **catch** block, and may affect the return value of a method. Therefore, ensure that the **finally** code block can stop properly.
727
728**[Incorrect Example]**
729
730```
731function foo() {
732  try {
733    // ...
734    return 1;
735  } catch (err) {
736    // ...
737    return 2;
738  } finally {
739    return 3;
740 }
741}
742```
743
744**[Correct Example]**
745
746```
747function foo() {
748  try {
749    // ...
750    return 1;
751  } catch (err) {
752    // ...
753    return 2;
754  } finally {
755    console.log('XXX!');
756  }
757}
758```
759
760### Do Not Use ESObject
761
762**[Category]** Recommendation
763
764**[Description]**
765
766**ESObject** is mainly used for type annotation in ArkTS and TS/JS cross-language calls. Using it in other scenarios introduces unnecessary cross-language calls and causes extra performance overhead.
767
768**[Incorrect Example]**
769
770```
771// lib.ets
772export interface I {
773  sum: number
774}
775
776export function getObject(value: number): I {
777  let obj: I = { sum: value };
778  return obj
779}
780
781// app.ets
782import { getObject } from 'lib'
783let obj: ESObject = getObject(123);
784```
785
786**[Correct Example]**
787
788```
789// lib.ets
790export interface I {
791  sum: number
792}
793
794export function getObject(value: number): I {
795  let obj: I = { sum: value };
796  return obj
797}
798
799// app.ets
800import { getObject, I } from 'lib'
801let obj: I = getObject(123);
802```
803
804### Use T[] for the Array Type
805
806**[Category]** Recommendation
807
808**[Description]**
809
810ArkTS provides two array types: **T[]** and **Array\<T>**. To improve code readability, you are advised to use **T[]** to represent all array types.
811
812**[Incorrect Example]**
813
814```
815let x: Array<number> = [1, 2, 3];
816let y: Array<string> = ['a', 'b', 'c'];
817```
818
819**[Correct Example]**
820
821```
822// Use the T[] syntax.
823let x: number[] = [1, 2, 3];
824let y: string[] = ['a', 'b', 'c'];
825```
826