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