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