1# Introduction 2 3Welcome to the tutorial for ArkTS, a TypeScript-based programming language designed specifically to build high-performance mobile applications! 4 5ArkTS is optimized to provide better performance and efficiency, while still maintaining the familiar syntax of TypeScript. 6 7As mobile devices continue to become more prevalent in our daily lives, there is a growing need for programming languages optimized for the mobile environment. Many current programming languages were not designed with mobile devices in mind, resulting in slow and inefficient applications that drain battery life. ArkTS has been specifically designed to address such concerns by prioritizing higher execution efficiency. 8 9ArkTS is based on the popular programming language TypeScript that extends JavaScript by adding type definitions. TypeScript is well-loved by many developers as it provides a more structured approach to coding in JavaScript. ArkTS aims to keep the look and feel of TypeScript to enable a seamless transition for the existing TypeScript developers, and to let mobile developers learn ArkTS quickly. 10 11One of the key features of ArkTS is its focus on low runtime overhead. 12ArkTS imposes stricter limitations on the TypeScript's dynamically typed features, reducing runtime overhead and allowing faster execution. By eliminating the dynamically typed features from the language, ArkTS code can be compiled ahead-of-time more efficiently, resulting in faster application startup and lower power consumption. 13 14Interoperability with JavaScript was a critical consideration in the ArkTS language design. Many mobile app developers already have TypeScript and JavaScript code and libraries they would want to reuse. ArkTS has been designed for seamless JavaScript interoperability, making it easy for the developers to integrate the JavaScript code into their applications and vice versa. This will allow the developers to use their existing codebases and libraries to leverage the power of our new language. 15 16To ensure best experience for UI app development for OpenHarmony ecosystem, ArkTS provides support for ArkUI, including its declarative syntax and other features. Since this feature is outside the scope of the "stock" TypeScript, a verbose ArkUI example is provided in a separate chapter. 17 18This tutorial will guide you through the core features, syntax, and best practices of ArkTS. After reading this tutorial through the end, you will be able to build performant and efficient mobile applications in ArkTS.<!--Del--> For details about programming specifications, see [ArkTS Coding Style Guide](../../contribute/OpenHarmony-ArkTS-coding-style-guide.md).<!--DelEnd--> 19 20## The Basics 21 22### Declarations 23 24Declarations in ArkTS introduce: 25 26- Variables 27- Constants 28- Functions 29- Types 30 31#### Variable Declaration 32 33A declaration starting with the keyword `let` introduces a variable which can have different values during program execution. 34 35```typescript 36let hi: string = 'hello'; 37hi = 'hello, world'; 38``` 39 40#### Constant Declaration 41 42A declaration starting with the keyword `const` introduces a read-only constant that can be assigned only once. 43 44```typescript 45const hello: string = 'hello'; 46``` 47 48A compile-time error occurs if a new value is assigned to a constant. 49 50#### Automatic Type Inference 51 52As ArkTS is a statically typed language, the types of all entities, like variables and constants, have to be known at compile time. 53 54However, developers do not need to explicitly specify the type of a declared entity if a variable or a constant declaration contains an initial value. 55 56All cases that allow the type to be inferred automatically are specified in the ArkTS Specification. 57 58Both variable declarations are valid, and both variables are of the `string` type: 59 60```typescript 61let hi1: string = 'hello'; 62let hi2 = 'hello, world'; 63``` 64 65### Types 66 67#### Numeric Types 68 69ArkTS has `number` and `Number` numeric types. Any integer and floating-point values can be assigned to a variable of these types. 70 71Numeric literals include integer literals and floating-point literals 72with the decimal base. 73 74Integer literals include the following: 75 76* Decimal integers that consist of a sequence of digits. For example: `0`, `117`, `-345`. 77* Hexadecimal integers that start with 0x (or 0X), and can contain digits (0-9) and letters a-f or A-F. For example: `0x1123`, `0x00111`, `-0xF1A7`. 78* Octal integers that start with 0o (or 0O) and can only contain digits (0-7). For example: `0o777`. 79* Binary integers that start with 0b (or 0B), and can only contain the digits 0 and 1. For example: `0b11`, `0b0011`, `-0b11`. 80 81A floating-point literal includes the following: 82 83* Decimal integer, optionally signed (i.e., prefixed with "+" or "-"); 84* Decimal point ("."). 85* Fractional part (represented by a string of decimal digits). 86* Exponent part that starts with "e" or "E", followed by an optionally signed (i.e., prefixed with "+" or "-") integer. 87 88Example: 89 90```typescript 91let n1 = 3.14; 92let n2 = 3.141592; 93let n3 = .5; 94let n4 = 1e2; 95 96function factorial(n: number): number { 97 if (n <= 1) { 98 return 1; 99 } 100 return n * factorial(n - 1); 101} 102 103factorial(n1) // 7.660344000000002 104factorial(n2) // 7.680640444893748 105factorial(n3) // 1 106factorial(n4) // 9.33262154439441e+157 107``` 108 109#### `Boolean` 110 111The `boolean` type represents logical values that are either `true` or `false`. 112 113Usually variables of this type are used in conditional statements: 114 115```typescript 116let isDone: boolean = false; 117 118// ... 119 120if (isDone) { 121 console.log ('Done!'); 122} 123``` 124 125#### `String` 126 127A `string` is a sequence of characters; some characters can be set by using escape sequences. 128 129A `string` literal consists of zero or more characters enclosed in single (') or double quotes ("). The special form of string literals are template literals enclosed in backtick quotes (\`). 130 131```typescript 132let s1 = 'Hello, world!\n'; 133let s2 = 'this is a string'; 134let a = 'Success'; 135let s3 = `The result is ${a}`; 136``` 137 138#### `Void` Type 139 140The `void` type is used to specify that a function does not return a value. 141This type has the only one value which is also `void`. As `void` is 142a reference type, it can be used as type argument for generic types. 143 144```typescript 145class Class<T> { 146 //... 147} 148let instance: Class <void> 149``` 150 151#### `Object` Type 152 153An `Object` class type is a base type for all reference types. Any value, including values of primitive types (they will be automatically boxed), can be directly assigned to variables of the type `Object`. 154 155#### `Array` Type 156 157An `array` is an object comprised of elements of data types assignable to the element type specified in the array declaration. 158A value of an `array` is set by using *array composite literal*, that is a list of zero or more expressions enclosed in square brackets ([]). Each expression represents an element of the `array`. The length of the `array` is set by the number of expressions. Index of the first array element is 0. 159 160The following example creates the `array` with three elements: 161 162```typescript 163let names: string[] = ['Alice', 'Bob', 'Carol']; 164``` 165 166#### `Enum` Type 167 168An `enum` type is a value type with a defined set of named values called enum constants. 169In order to be used, an `enum` constant must be prefixed with an enum `type` name. 170 171```typescript 172enum ColorSet { Red, Green, Blue } 173let c: ColorSet = ColorSet.Red; 174``` 175 176A constant expression can be used to explicitly set the value of an `enum` constant. 177 178```typescript 179enum ColorSet { White = 0xFF, Grey = 0x7F, Black = 0x00 } 180let c: ColorSet = ColorSet.Black 181``` 182 183#### `Union` Type 184 185A `union` type is a reference type which is created as a combination of other types. Values of union types can be valid values of all types a union was created from. 186 187```typescript 188class Cat { 189 name: string = 'cat'; 190 // ... 191} 192class Dog { 193 name: string = 'dog'; 194 // ... 195} 196class Frog { 197 name: string = 'frog'; 198 // ... 199} 200type Animal = Cat | Dog | Frog | number 201// Cat, Dog, and Frog are some types (class or interface ones) 202 203let animal: Animal = new Cat(); 204animal = new Frog(); 205animal = 42; 206// One may assign the variable of the union type with any valid value 207``` 208 209There are different mechanisms to get a value of a particular type from a union. 210 211Example: 212 213```typescript 214class Cat { sleep () {}; meow () {} } 215class Dog { sleep () {}; bark () {} } 216class Frog { sleep () {}; leap () {} } 217 218type Animal = Cat | Dog | Frog; 219 220function foo(animal: Animal) { 221 if (animal instanceof Frog) { 222 animal.leap(); // animal is of type Frog here 223 } 224 animal.sleep(); // Any animal can sleep 225} 226``` 227 228#### Type `Aliases` 229 230Type `aliases` provides names for anonymous types (array, function, object literal or union types) or alternative names for existing types. 231 232```typescript 233type Matrix = number[][]; 234type Handler = (s: string, no: number) => string; 235type Predicate <T> = (x: T) => boolean; 236type NullableObject = Object | null; 237``` 238 239### Operators 240 241#### Assignment Operators 242 243Simple assignment operator '=' is used as in "x = y". 244 245Compound assignment operators combine an assignment with an operator, where `x op = y` equals `x = x op y`. 246 247Compound assignment operators are as follows: `+=`, `-=`, `*=`, `/=`, `%=`, `<<=`, `>>=`, `>>>=`, `&=`, `|=`, `^=`. 248 249#### Comparison Operators 250 251| Operator | Description | 252| -------- | ------------------------------------------------------------ | 253| `===` | Returns true if both operands are strict equal. | 254| `!==` | Returns true if both operands are nots trict equal. | 255| `==` | Returns true if both operands are equal. | 256| `!=` | Returns true if both operands are not equal. | 257| `>` | Returns true if the left operand is greater than the right. | 258| `>=` | Returns true if the left operand is greater than or equal to the right. | 259| `<` | Returns true if the left operand is less than the right. | 260| `<=` | Returns true if the left operand is less than or equal to the right. | 261#### Arithmetic Operators 262 263Unary operators are `-`, `+`, `--` and `++`. 264 265Binary operators are as follows: 266 267| Operator | Description | 268|------------|--------------------------| 269| `+` | addition | 270| `-` | subtraction | 271| `*` | multiplication | 272| `/` | division | 273| `%` | remainder after division | 274#### Bitwise Operators 275 276| Operator | Description | 277|------------|-----------------------------------------------------------------------------------------------------------------| 278| `a & b` | Bitwise AND: sets each bit to 1 if the corresponding bits of both operands are 1, otherwise to 0. | 279| `a \| b` | Bitwise OR: sets each bit to 1 if at least one of the corresponding bits of both operands is 1, otherwise to 0. | 280| `a ^ b` | Bitwise XOR: sets each bit to 1 if the corresponding bits of both operands are different, otherwise to 0. | 281| `~ a` | Bitwise NOT: inverts the bits of the operand. | 282| `a << b` | Shift left: shifts the binary representation of *a* to the left by *b* bits. | 283| `a >> b` | Arithmetic right shift: shifts the binary representation of *a* to the right by *b* bits with sign-extension. | 284| `a >>> b` | Logical right shift: shifts the binary representation of *a* to the right by *b* bits with zero-extension. | 285#### Logical Operators 286 287| Operator | Description | 288|------------|---------------| 289| `a && b` | Logical AND | 290| `a \|\| b` | Logical OR | 291| `! a` | Logical NOT | 292### Statements 293 294#### `If` Statements 295 296An `if` statement is used to execute a sequence of statements when a logical condition is `true`, or another set of statements (if provided) otherwise. 297 298The `else` part can also contain more `if` statements. 299 300An `if` statement looks as follows: 301 302```typescript 303if (condition1) { 304 // statements1 305} else if (condition2) { 306 // statements2 307} else { 308 // else_statements 309} 310``` 311 312All conditional expressions must be of the type `boolean` or other types (`string`, `number`, etc.). For types other than `boolean`, implicit conversion rules apply: 313 314```typescript 315let s1 = 'Hello'; 316if (s1) { 317 console.log(s1); // prints 'Hello' 318} 319 320let s2 = 'World'; 321if (s2.length != 0) { 322 console.log(s2); // prints 'World' 323} 324``` 325 326#### `Switch` Statements 327 328A `switch` statement is used to execute a sequence of statements that match the value of a switch expression. 329 330A `switch` statement looks as follows: 331 332```typescript 333switch (expression) { 334 case label1: // will be executed if label1 is matched 335 // ... 336 // statements1 337 // ... 338 break; // Can be omitted 339 case label2: 340 case label3: // will be executed if label2 or label3 is matched 341 // ... 342 // statements23 343 // ... 344 break; // Can be omitted 345 default: 346 // default_statements 347} 348``` 349 350If the value of a `switch` expression equals the value of some label, then the corresponding statements are executed. 351 352If there is no match, and the `switch` has the default clause, then the default statements are executed. 353 354An optional `break` statement allows you to break out of the `switch` and continue executing the statement that follows the `switch`. 355 356If there is no `break`, then the next statements in the `switch` are executed. 357 358#### Conditional Expressions 359 360The conditional expression `? :` uses the `boolean` value of the first expression to decide which of two other expressions to evaluate. 361 362A conditional expression looks as follows: 363 364```typescript 365condition ? expression1 : expression2 366``` 367 368If that logical expression is truthy(a value that is considered `true`), then the first expression is used as the result of the ternary expression; otherwise, the second expression is used. 369 370Example: 371 372```typescript 373let isValid = Math.random() > 0.5 ? true : false; 374let message = isValid ? 'Valid' : 'Failed'; 375``` 376 377#### `For` Statements 378 379A `for` statement is executed repeatedly until the specified loop exit condition is `false`. 380 381A `for` statement looks as follows: 382 383```typescript 384for ([init]; [condition]; [update]) { 385 statements 386} 387``` 388 389When a `for` statement is executed, the following process takes place: 390 3911. An `init` expression is executed, if any. This expression usually initializes one or more loop counters. 3922. The condition is evaluated. If the value of condition is truthy(a value that is considered `true`), or if the conditional expression is omitted, then the statements in the `for` body are to be executed. If the value of condition is falsy(a value that is considered `false`), then the `for` loop terminates. 3933. The statements of the `for` body are executed. 3944. If there is an `update` expression, then the `update` expression is executed. 3955. Go back to step 2. 396 397Example: 398 399```typescript 400let sum = 0; 401for (let i = 0; i < 10; i += 2) { 402 sum += i; 403} 404``` 405 406#### `For-of` Statements 407 408`for-of` statements are used to iterate over an array or string. 409 410A `for-of` statement looks as follows: 411 412```typescript 413for (forVar of expression) { 414 statements 415} 416``` 417 418Example: 419 420```typescript 421for (let ch of 'a string object') { 422 /* process ch */ 423} 424``` 425 426#### `While` Statements 427 428A `while` statement has its body statements executed as long as the specified condition evaluates to `true`. 429 430A `while` statement looks as follows: 431 432```typescript 433while (condition) { 434 statements 435} 436``` 437 438Example: 439 440```typescript 441let n = 0; 442let x = 0; 443while (n < 3) { 444 n++; 445 x += n; 446} 447``` 448 449#### `Do-while` Statements 450 451`do-while` statements are executed repetitively until a specified condition evaluates to `false`. 452 453A `do-while` statement looks as follows: 454 455```typescript 456do { 457 statements 458} while (condition) 459``` 460 461Example: 462 463```typescript 464let i = 0; 465do { 466 i += 1; 467} while (i < 10) 468``` 469 470#### `Break` Statements 471 472A `break` statement is used to terminate any `loop` statement or `switch`. 473 474Example: 475 476```typescript 477let x = 0; 478while (true) { 479 x++; 480 if (x > 5) { 481 break; 482 } 483} 484``` 485 486A `break` statement with a label identifier transfers control out of the enclosing statement to the one which has the same label identifier. 487 488Example: 489 490```typescript 491let x = 1; 492label: while (true) { 493 switch (x) { 494 case 1: 495 // statements 496 break label; // breaks the while 497 } 498} 499``` 500 501#### `Continue` Statements 502 503A `continue` statement stops the execution of the current loop iteration and passes control to the next iteration. 504 505Example: 506 507```typescript 508let sum = 0; 509for (let x = 0; x < 100; x++) { 510 if (x % 2 == 0) { 511 continue; 512 } 513 sum += x; 514} 515``` 516 517#### `Throw` and `Try` Statements 518 519A `throw` statement is used to throw an exception or an error: 520 521```typescript 522throw new Error('this error') 523``` 524 525A `try` statement is used to catch and handle an exception or an error: 526 527```typescript 528try { 529 // try block 530} catch (e) { 531 // handle the situation 532} 533``` 534 535The example below shows the `throw` and `try` statements used to handle the zero division case: 536 537```typescript 538class ZeroDivisor extends Error {} 539 540function divide (a: number, b: number): number{ 541 if (b == 0) throw new ZeroDivisor(); 542 return a / b; 543} 544 545function process (a: number, b: number) { 546 try { 547 let res = divide(a, b); 548 console.log('result: ' + res); 549 } catch (x) { 550 console.log('some error'); 551 } 552} 553``` 554 555`finally` clause is also supported: 556 557```typescript 558function processData(s: string) { 559 let error: Error | null = null; 560 561 try { 562 console.log('Data processed: ' + s); 563 // ... 564 // Throwing operations 565 // ... 566 } catch (e) { 567 error = e as Error; 568 // ... 569 // More error handling 570 // ... 571 } finally { 572 if (error != null) { 573 console.log(`Error caught: input='${s}', message='${error.message}'`); 574 } 575 } 576} 577``` 578 579## Functions 580 581### Function Declarations 582 583A function declaration introduces a named function, specifying its name, parameters, return type and body. 584 585Below is a simple function with two string parameters and string return type: 586 587```typescript 588function add(x: string, y: string): string { 589 let z: string = `${x} ${y}`; 590 return z; 591} 592``` 593 594For every parameter its type annotation must be specified. 595An optional parameter allows you to omit the corresponding argument when calling a function. The last parameter of a function can be a rest parameter. 596 597### Optional Parameters 598 599An optional parameter has the form `name?: Type`. 600 601```typescript 602function hello(name?: string) { 603 if (name == undefined) { 604 console.log('Hello!'); 605 } else { 606 console.log(`Hello, ${name}!`); 607 } 608} 609``` 610 611Another form contains an expression that specifies a default value. 612If the corresponding argument to such parameter is omitted in a function call, then this parameter's value is default. 613 614```typescript 615function multiply(n: number, coeff: number = 2): number { 616 return n * coeff; 617} 618multiply(2); // returns 2*2 619multiply(2, 3); // returns 2*3 620``` 621 622### The Rest Parameter 623 624The last parameter of a function can be a rest parameter. It allows functions or methods to take unlimited number of arguments. 625 626```typescript 627function sum(...numbers: number[]): number { 628 let res = 0; 629 for (let n of numbers) 630 res += n; 631 return res; 632} 633 634sum(); // returns 0 635sum(1, 2, 3); // returns 6 636``` 637 638### Return Types 639 640If function return type can be inferred from its body content, then it can be omitted from the function declaration. 641 642```typescript 643// Explicit return type 644function foo(): string { return 'foo'; } 645 646// Implicit return type inferred as string 647function goo() { return 'goo'; } 648``` 649 650The return type of a function that does not need to return a value can be explicitly specified as `void` or omitted altogether. No return statement is needed for such functions. 651 652Both notations below are valid: 653 654```typescript 655function hi1() { console.log('hi'); } 656function hi2(): void { console.log('hi'); } 657``` 658 659### Function Scope 660 661Variables and other entities defined in a function are local to the function and cannot be accessed from the outside. 662 663If the name of a variable defined in the function is equal to the name of an entity in the outer scope, then the local definition shadows the outer entity. 664 665### Function Calls 666 667Calling a function actually leads to the execution of its body, while the arguments of the call are assigned to the function parameters. 668 669If the function is defined as follows: 670 671```typescript 672function join(x: string, y: string): string { 673 let z: string = `${x} ${y}`; 674 return z; 675} 676``` 677 678then it is called with two arguments of the type `string`: 679 680```typescript 681let x = join('hello', 'world'); 682console.log(x); 683``` 684 685## Function Types 686 687Function types are commonly used as follows to define callbacks: 688 689```typescript 690type trigFunc = (x: number) => number // this is a function type 691 692function do_action(f: trigFunc) { 693 f(3.141592653589); // call the function 694} 695 696do_action(Math.sin); // pass the function as the parameter 697``` 698 699### Arrow Functions (Lambdas Functions) 700 701A function can be defined as an arrow function, for example: 702 703```typescript 704let sum = (x: number, y: number): number => { 705 return x + y; 706} 707``` 708 709An arrow function return type can be omitted; in such case, it is inferred from the function body. 710 711An expression can be specified as an arrow function to make the notation shorter, i.e., the following two notations are equivalent: 712 713```typescript 714let sum1 = (x: number, y: number) => { return x + y; } 715let sum2 = (x: number, y: number) => x + y 716``` 717 718### Closure 719 720A closure is the combination of a function and the lexical environment within which that function was declared. This environment consists of any local variables that were in-scope at the time the closure was created. 721 722In the following example, **z** is a reference to the instance of the function **g** that is created when **f** is executed. The instance of **g** maintains a reference to its lexical environment, within which the variable **count** exists. For this reason, when **z** is invoked, the variable **count** remains available for use. 723 724```typescript 725function f(): () => number { 726 let count = 0; 727 let g = (): number => { count++; return count; }; 728 return g; 729} 730 731let z = f(); 732z(); // output: 1 733z(); // output: 2 734``` 735 736### Function Overload Signatures 737 738A function can be specified to be called in different ways by writing overload signatures. To do so, several functions' headers that have the same name but different signatures are written and immediately followed by the single implementation function. 739 740```typescript 741function foo(x: number): void; /* 1st signature */ 742function foo(x: string): void; /* 2nd signature */ 743function foo(x: number | string): void { /* Implementation signature */ 744} 745 746foo(123); // ok, 1st signature is used 747foo('aa'); // ok, 2nd signature is used 748``` 749 750An error occurs if two overload signatures have identical parameter lists. 751 752## Classes 753 754A class declaration introduces a new type and defines its fields, methods and constructors. 755 756In the following example, class `Person` is defined, which has fields **name** and **surname**, constructor, and a method `fullName`: 757 758```typescript 759class Person { 760 name: string = ''; 761 surname: string = ''; 762 constructor (n: string, sn: string) { 763 this.name = n; 764 this.surname = sn; 765 } 766 fullName(): string { 767 return this.name + ' ' + this.surname; 768 } 769} 770``` 771 772After the class is defined, its instances can be created by using the keyword `new`: 773 774```typescript 775let p = new Person('John', 'Smith'); 776console.log(p.fullName()); 777``` 778 779or an instance can be created by using object literals: 780 781```typescript 782class Point { 783 x: number = 0; 784 y: number = 0; 785} 786let p: Point = {x: 42, y: 42}; 787``` 788 789### Fields 790 791A field is a variable of some type that is declared directly in a class. 792 793Classes may have instance fields, static fields or both. 794 795#### Instance Fields 796 797Instance fields exist on every instance of a class. Each instance has its own set of instance fields. 798 799An instance of the class is used to access an instance field. 800 801```typescript 802class Person { 803 name: string = ''; 804 age: number = 0; 805 constructor(n: string, a: number) { 806 this.name = n; 807 this.age = a; 808 } 809 810 getName(): string { 811 return this.name; 812 } 813} 814 815let p1 = new Person('Alice', 25); 816p1.name; 817let p2 = new Person('Bob', 28); 818p2.getName(); 819``` 820 821#### Static Fields 822 823The keyword `static` is used to declare a field as static. Static fields belong to the class itself, and all instances of the class share one static field. 824 825The class name is used to access a static field: 826 827```typescript 828class Person { 829 static numberOfPersons = 0; 830 constructor() { 831 // ... 832 Person.numberOfPersons++; 833 // ... 834 } 835} 836 837Person.numberOfPersons; 838``` 839 840#### Field Initializers 841 842ArkTS requires that all fields are explicitly initialized with some values either when the field is declared or in the `constructor`. This is similar to `strictPropertyInitialization` mode of the standard TypeScript. Such behavior is enforced to minimize the number of unexpected runtime errors and achieve better performance. 843 844The following code (invalid in ArkTS) is error-prone: 845 846```typescript 847class Person { 848 name: string; // undefined 849 850 setName(n:string): void { 851 this.name = n; 852 } 853 854 getName(): string { 855 // Return type "string" hides from the developers the fact 856 // that name can be undefined. The most correct would be 857 // to write the return type as "string | undefined". By doing so 858 // we tell the users of our API about all possible return values. 859 return this.name; 860 } 861} 862 863let jack = new Person(); 864// Let's assume that the developer forgets to call setName: 865// jack.setName('Jack') 866jack.getName().length; // runtime exception: name is undefined 867``` 868 869Here is how it should look in ArkTS: 870 871```typescript 872class Person { 873 name: string = ''; 874 875 setName(n:string): void { 876 this.name = n; 877 } 878 879 // The type is always string, no other "hidden options". 880 getName(): string { 881 return this.name; 882 } 883} 884 885 886let jack = new Person(); 887// Let's assume that the developer forgets to call setName: 888// jack.setName('Jack') 889jack.getName().length; // 0, no runtime error 890``` 891 892And here how our code behaves if the field `name` can be `undefined` 893 894```typescript 895class Person { 896 name?: string; // The field may be undefined 897 898 setName(n:string): void { 899 this.name = n; 900 } 901 902 // Compile-time error: 903 // name can be "undefined", so we cannot say to those who use this API 904 // that it returns only strings: 905 getNameWrong(): string { 906 return this.name; 907 } 908 909 getName(): string | undefined { // Return type matches the type of name 910 return this.name; 911 } 912} 913 914let jack = new Person() 915// Let's assume that the developer forgets to call setName: 916// jack.setName('Jack') 917 918// Compile-time(!) error: Compiler suspects that we 919// may possibly access something undefined and won't build the code: 920jack.getName().length; // The code won't build and run 921 922jack.getName()?.length; // Builds ok, no runtime error 923``` 924 925#### Getters and Setters 926 927Setters and getters can be used to provide controlled access to object properties. 928 929In the following example, a setter is used to forbid setting invalid values of the '_age' property: 930 931```typescript 932class Person { 933 name: string = ''; 934 private _age: number = 0; 935 get age(): number { return this._age; } 936 set age(x: number) { 937 if (x < 0) { 938 throw Error('Invalid age argument'); 939 } 940 this._age = x; 941 } 942} 943 944let p = new Person(); 945p.age; // 0 946p.age = -42; // Error will be thrown as an attempt to set incorrect age 947``` 948 949A class can define a getter, a setter or both. 950 951### Methods 952 953A method is a function that belongs to a class. 954A class can define instance methods, static methods or both. 955A static method belongs to the class itself, and can have access to static fields only. 956A `while` instance method has access to both static (class) fields and instance fields including private ones of its class. 957 958### Instance Methods 959 960The example below illustrates how instanced methods work. 961The `calculateArea` method calculates the area of a rectangle by multiplying the height by the width: 962 963```typescript 964class RectangleSize { 965 private height: number = 0; 966 private width: number = 0; 967 constructor(height: number, width: number) { 968 this.height = height; 969 this.width = width; 970 } 971 calculateArea(): number { 972 return this.height * this.width; 973 } 974} 975``` 976 977To use an instance method, it must be called on an instance of the class: 978 979```typescript 980let square = new RectangleSize(10, 10); 981square.calculateArea(); // output: 100 982``` 983 984#### Static Methods 985 986The keyword `static` is used to declare a method as static. Static methods belong to the class itself and have access to static fields only. 987A static method defines a common behavior of the class as a whole. 988 989The class name is used to call a static method: 990 991```typescript 992class Cl { 993 static staticMethod(): string { 994 return 'this is a static method.'; 995 } 996} 997console.log(Cl.staticMethod()); 998``` 999 1000#### Inheritance 1001 1002A class can extend another class. 1003The class that is being extended by another class is called ‘*base class*’, ‘parent class’, or ‘superclass’. 1004The class that extends another class is called ‘*extended class*’, ‘derived class’, or ‘subclass’. 1005 1006An extended class can implement several interfaces by using the following syntax: 1007 1008```typescript 1009class [extends BaseClassName] [implements listOfInterfaces] { 1010 // ... 1011} 1012``` 1013 1014An extended class inherits fields and methods, but not constructors from the base class, and can add its own fields and methods, as well as override methods defined by the base class. 1015 1016Example: 1017 1018```typescript 1019class Person { 1020 name: string = ''; 1021 private _age = 0; 1022 get age(): number { 1023 return this._age; 1024 } 1025} 1026class Employee extends Person { 1027 salary: number = 0; 1028 calculateTaxes(): number { 1029 return this.salary * 0.42; 1030 } 1031} 1032``` 1033 1034A class containing the `implements` clause must implement all methods defined in all listed interfaces, except the methods defined with default implementation. 1035 1036```typescript 1037interface DateInterface { 1038 now(): string; 1039} 1040class MyDate implements DateInterface { 1041 now(): string { 1042 // implementation is here 1043 return 'now'; 1044 } 1045} 1046``` 1047 1048#### Access to Super 1049 1050The keyword `super` can be used to access instance fields, instance methods and constructors from the super class. 1051 1052It is often used to extend basic functionality of subclass with the required behavior taken from the super class: 1053 1054```typescript 1055class RectangleSize { 1056 protected height: number = 0; 1057 protected width: number = 0; 1058 1059 constructor (h: number, w: number) { 1060 this.height = h; 1061 this.width = w; 1062 } 1063 1064 draw() { 1065 /* draw bounds */ 1066 } 1067} 1068class FilledRectangle extends RectangleSize { 1069 color = '' 1070 constructor (h: number, w: number, c: string) { 1071 super(h, w); // call of super constructor 1072 this.color = c; 1073 } 1074 1075 draw() { 1076 super.draw(); // call of super methods 1077 // super.height - can be used here 1078 /* fill rectangle */ 1079 } 1080} 1081``` 1082 1083#### Override Methods 1084 1085A subclass can override implementation of a method defined in its superclass. 1086An overridden method must have the same types of parameters, and same or derived return type as the original method. 1087 1088```typescript 1089class RectangleSize { 1090 // ... 1091 area(): number { 1092 // implementation 1093 return 0; 1094 } 1095} 1096class Square extends RectangleSize { 1097 private side: number = 0; 1098 area(): number { 1099 return this.side * this.side; 1100 } 1101} 1102``` 1103 1104#### Method Overload Signatures 1105 1106A method can be specified to be called in different ways by writing overload signatures. To do so, several method headers that have the same name but different signatures are written and immediately followed by the single implementation method. 1107 1108```typescript 1109class C { 1110 foo(x: number): void; /* 1st signature */ 1111 foo(x: string): void; /* 2nd signature */ 1112 foo(x: number | string): void { /* implementation signature */ 1113 } 1114} 1115let c = new C(); 1116c.foo(123); // ok, 1st signature is used 1117c.foo('aa'); // ok, 2nd signature is used 1118``` 1119 1120An error occurs if two overload signatures have the same name and identical parameter lists. 1121 1122### Constructors 1123 1124A class declaration may contain a constructor that is used to initialize object state. 1125 1126A constructor is defined as follows: 1127 1128```typescript 1129constructor ([parameters]) { 1130 // ... 1131} 1132``` 1133 1134If no constructor is defined, then a default constructor with an empty parameter list is created automatically, for example: 1135 1136```typescript 1137class Point { 1138 x: number = 0; 1139 y: number = 0; 1140} 1141let p = new Point(); 1142``` 1143 1144In this case the default constructor fills the instance fields with default values for the field types. 1145 1146#### Constructors in Derived Class 1147 1148The first statement of a constructor body can use the keyword `super` to explicitly call a constructor of the direct superclass. 1149 1150```typescript 1151class RectangleSize { 1152 constructor(width: number, height: number) { 1153 // ... 1154 } 1155} 1156class Square extends RectangleSize { 1157 constructor(side: number) { 1158 super(side, side); 1159 } 1160} 1161``` 1162 1163#### Constructor Overload Signatures 1164 1165A constructor can be specified to be called in different ways by writing overload signatures. To do so, several constructor headers that have the same name but different signatures are written and immediately followed by the single implementation constructor. 1166 1167```typescript 1168class C { 1169 constructor(x: number) /* 1st signature */ 1170 constructor(x: string) /* 2nd signature */ 1171 constructor(x: number | string) { /* Implementation signature */ 1172 } 1173} 1174let c1 = new C(123); // ok, 1st signature is used 1175let c2 = new C('abc'); // ok, 2nd signature is used 1176``` 1177 1178An error occurs if two overload signatures have the same name and identical parameter lists. 1179 1180### Visibility Modifiers 1181 1182Both methods and properties of a class can have visibility modifiers. 1183 1184There are several visibility modifiers: 1185 1186- `private` 1187- `protected` 1188- `public` 1189 1190The default visibility is `public`. 1191 1192#### Public Visibility 1193 1194The `public` members (fields, methods, constructors) of a class are visible in any part of the program, where their class is visible. 1195 1196### Private Visibility 1197 1198A `private` member cannot be accessed outside the class it is declared in. 1199Example: 1200 1201```typescript 1202class C { 1203 public x: string = ''; 1204 private y: string = ''; 1205 set_y (new_y: string) { 1206 this.y = new_y // ok, as y is accessible within the class itself 1207 } 1208} 1209let c = new C(); 1210c.x = 'a'; // ok, the field is public 1211c.y = 'b'; // compile-time error: 'y' is not visible 1212``` 1213 1214#### Protected Visibility 1215 1216The modifier `protected` acts much like the modifier `private`, but the `protected` members are also accessible in derived classes. 1217Example: 1218 1219```typescript 1220class Base { 1221 protected x: string = ''; 1222 private y: string = ''; 1223} 1224class Derived extends Base { 1225 foo() { 1226 this.x = 'a'; // ok, access to protected member 1227 this.y = 'b'; // compile-time error, 'y' is not visible, as it is private 1228 } 1229} 1230``` 1231 1232### Object Literals 1233 1234An object literal is an expression that can be used to create a class instance and provide some initial values. It can be used instead of the expression `new` as it is more convenient in some cases. 1235 1236A class composite is written as a comma-separated list of name-value pairs enclosed in '{' and '}'. 1237 1238```typescript 1239class C { 1240 n: number = 0; 1241 s: string = ''; 1242} 1243 1244let c: C = {n: 42, s: 'foo'}; 1245``` 1246 1247Due to the static typing of the ArkTS, object literals can be used in a context where the class or interface type of the object literal can be inferred as in the example above. Other valid cases are illustrated below: 1248 1249```typescript 1250class C { 1251 n: number = 0; 1252 s: string = ''; 1253} 1254 1255function foo(c: C) {} 1256 1257let c: C; 1258 1259c = {n: 42, s: 'foo'}; // type of the variable is used 1260foo({n: 42, s: 'foo'}); // type of the parameter is used 1261 1262function bar(): C { 1263 return {n: 42, s: 'foo'}; // return type is used 1264} 1265``` 1266 1267The type of an array element or of a class field can also be used: 1268 1269```typescript 1270class C { 1271 n: number = 0; 1272 s: string = ''; 1273} 1274let cc: C[] = [{n: 1, s: 'a'}, {n: 2, s: 'b'}]; 1275``` 1276 1277#### Object Literals of Record Type 1278 1279The generic Record<K, V> type is used to map the properties of a type (Key type) to another type (Value type). 1280 1281A special form of object literal is used to initialize the value of such type: 1282 1283```typescript 1284let map: Record<string, number> = { 1285 'John': 25, 1286 'Mary': 21, 1287} 1288 1289map['John']; // 25 1290``` 1291 1292The K type can be either string or number, while V can be any type. 1293 1294```typescript 1295interface PersonInfo { 1296 age: number; 1297 salary: number; 1298} 1299let map: Record<string, PersonInfo> = { 1300 'John': { age: 25, salary: 10}, 1301 'Mary': { age: 21, salary: 20} 1302} 1303``` 1304 1305## Interfaces 1306 1307An interface declaration introduces a new type. Interfaces are a common way of defining contracts between various part of codes. 1308 1309Interfaces are used to write polymorphic code, which can be applied to any class instances that implement a particular interface. 1310 1311An interface usually contains properties and method headers. 1312 1313Examples: 1314 1315```typescript 1316interface Style { 1317 color: string; // property 1318} 1319interface AreaSize { 1320 calculateAreaSize(): number; // method header 1321 someMethod(): void; // method header 1322} 1323``` 1324 1325Examples of a class implementing an interface: 1326 1327```typescript 1328// Interface: 1329interface AreaSize { 1330 calculateAreaSize(): number; // method header 1331 someMethod(): void; // method header 1332} 1333 1334// Implementation: 1335class RectangleSize implements AreaSize { 1336 private width: number = 0; 1337 private height: number = 0; 1338 someMethod(): void { 1339 console.log('someMethod called'); 1340 } 1341 calculateAreaSize(): number { 1342 this.someMethod(); // calls another method and returns result 1343 return this.width * this.height; 1344 } 1345} 1346``` 1347 1348### Interface Properties 1349 1350An interface property can be in a form of field, getter, setter, or both getter and setter. 1351 1352A property field is just a shortcut notation of a getter/setter pair, and the following notations are equal: 1353 1354```typescript 1355interface Style { 1356 color: string; 1357} 1358``` 1359 1360```typescript 1361interface Style { 1362 get color(): string 1363 set color(x: string) 1364} 1365``` 1366 1367A class that implements an interface may also use a short or a long notation: 1368 1369```typescript 1370interface Style { 1371 color: string; 1372} 1373 1374class StyledRectangle implements Style { 1375 color: string = ''; 1376} 1377``` 1378 1379```typescript 1380interface Style { 1381 color: string; 1382} 1383 1384class StyledRectangle implements Style { 1385 private _color: string = ''; 1386 get color(): string { return this._color; } 1387 set color(x: string) { this._color = x; } 1388} 1389``` 1390 1391### Interface Inheritance 1392 1393An interface may extend other interfaces like in the example below: 1394 1395```typescript 1396interface Style { 1397 color: string; 1398} 1399 1400interface ExtendedStyle extends Style { 1401 width: number; 1402} 1403``` 1404 1405An extended interface contains all properties and methods of the interface it extends, and can also add its own properties and methods. 1406 1407## Generic Types and Functions 1408 1409Generic types and functions allow creating the code capable to work over a variety of types rather than a single type. 1410 1411### Generic Classes and Interfaces 1412 1413A class and an interface can be defined as generics, adding parameters to the type definition, like the type parameter `Element` in the following example: 1414 1415```typescript 1416class CustomStack<Element> { 1417 public push(e: Element):void { 1418 // ... 1419 } 1420} 1421``` 1422 1423To use type CustomStack, the type argument must be specified for each type parameter: 1424 1425```typescript 1426let s = new CustomStack<string>(); 1427s.push('hello'); 1428``` 1429 1430Compiler ensures type safety while working with generic types and functions. 1431See below: 1432 1433```typescript 1434let s = new CustomStack<string>(); 1435s.push(55); // That will be a compile-time error as 55 is not compatible with type string. 1436``` 1437 1438### Generic Constraints 1439 1440Type parameters of generic types can be bounded. For example, the `Key` type parameter in the `MyHashMap<Key, Value>` container must have the `hash` method. 1441 1442```typescript 1443interface Hashable { 1444 hash(): number; 1445} 1446class MyHashMap<Key extends Hashable, Value> { 1447 public set(k: Key, v: Value) { 1448 let h = k.hash(); 1449 // ... other code ... 1450 } 1451} 1452``` 1453 1454In the above example, the `Key` type extends `Hashable`, and all methods of `Hashable` interface can be called for keys. 1455 1456### Generic Functions 1457 1458Use a generic function to create a more universal code. Consider a function that returns the last element of the array: 1459 1460```typescript 1461function last(x: number[]): number { 1462 return x[x.length - 1]; 1463} 1464last([1, 2, 3]); // output: 3 1465``` 1466 1467If the same function needs to be defined for any array, then define it as a generic with a type parameter: 1468 1469```typescript 1470function last<T>(x: T[]): T { 1471 return x[x.length - 1]; 1472} 1473``` 1474 1475Now, the function can be used with any array. 1476 1477In a function call, type argument can be set explicitly or implicitly: 1478 1479```typescript 1480// Explicit type argument 1481last<string>(['aa', 'bb']); 1482last<number>([1, 2, 3]); 1483 1484// Implicit type argument: 1485// Compiler understands the type argument based on the type of the call arguments 1486last([1, 2, 3]); 1487``` 1488 1489### Generic Defaults 1490 1491Type parameters of generic types can have defaults. It allows using just the generic type name instead of specifying the actual type arguments. 1492The example below illustrates this for both classes and functions. 1493 1494```typescript 1495class SomeType {} 1496interface Interface <T1 = SomeType> { } 1497class Base <T2 = SomeType> { } 1498class Derived1 extends Base implements Interface { } 1499// Derived1 is semantically equivalent to Derived2 1500class Derived2 extends Base<SomeType> implements Interface<SomeType> { } 1501 1502function foo<T = number>(): T { 1503 // ... 1504} 1505foo(); 1506// such function is semantically equivalent to the call below 1507foo<number>(); 1508``` 1509 1510## Null Safety 1511 1512All types in ArkTS by default are non-nullable, so the value of a type cannot be null. 1513It is similar to TypeScript behavior in strict null checking mode (`strictNullChecks`), but the rules are stricter. 1514 1515In the example below, all lines cause a compile-time error: 1516 1517```typescript 1518let x: number = null; // Compile-time error 1519let y: string = null; // Compile-time error 1520let z: number[] = null; // Compile-time error 1521``` 1522 1523A variable that can have a null value is defined with a union type `T | null`. 1524 1525```typescript 1526let x: number | null = null; 1527x = 1; // ok 1528x = null; // ok 1529if (x != null) { /* do something */ } 1530``` 1531 1532### Non-Null Assertion Operator 1533 1534A postfix operator `!` can be used to assert that its operand is non-null. 1535 1536If applied to a null value, the operator throws an error. Otherwise, the type of the value is changed from `T | null` to `T`: 1537 1538```typescript 1539class A { 1540 value: number = 0; 1541} 1542 1543function foo(a: A | null) { 1544 a.value; // compile time error: cannot access to a nullable value 1545 1546 // ok, if the value of a is not null at runtime, the fields of a can be accessed; 1547 // If the value of runtime a is empty, a runtime exception occurs. 1548 a!.value; 1549} 1550``` 1551 1552### Null-Coalescing Operator 1553 1554The null-coalescing binary operator `??` checks whether the evaluation of the left-hand-side expression is equal to `null` or `undefined`. 1555If it is, then the result of the expression is the right-hand-side expression; otherwise, it is the left-hand-side expression. 1556 1557In other words, `a ?? b` equals the ternary operator `(a != null && a != undefined) ? a : b`. 1558 1559In the following example, the method `getNick` returns a nickname if it is set; otherwise, an empty string is returned: 1560 1561```typescript 1562class Person { 1563 // ... 1564 nick: string | null = null; 1565 getNick(): string { 1566 return this.nick ?? ''; 1567 } 1568} 1569``` 1570 1571### Optional Chaining 1572 1573Optional chaining operator `?.` allows writing code where the evaluation stops at an expression that is partially evaluated to `null` or `undefined`. 1574 1575```typescript 1576class Person { 1577 nick: string | null = null; 1578 spouse?: Person; 1579 1580 setSpouse(spouse: Person): void { 1581 this.spouse = spouse; 1582 } 1583 1584 getSpouseNick(): string | null | undefined { 1585 return this.spouse?.nick; 1586 } 1587 1588 constructor(nick: string) { 1589 this.nick = nick; 1590 this.spouse = undefined; 1591 } 1592} 1593``` 1594 1595**Note**: The return type of `getSpouseNick` must be `string | null | undefined`, as the method can return `null` or `undefined`. 1596 1597An optional chain can be of any length and contain any number of `?.` operators. 1598 1599In the following sample, the output is a person's spouse nickname if that person has a spouse, and the spouse has a nickname. 1600 1601Otherwise, the output is `undefined`: 1602 1603```typescript 1604class Person { 1605 nick: string | null = null; 1606 spouse?: Person; 1607 1608 constructor(nick: string) { 1609 this.nick = nick; 1610 this.spouse = undefined; 1611 } 1612} 1613 1614let p: Person = new Person('Alice'); 1615p.spouse?.nick; // undefined 1616``` 1617 1618## Modules 1619 1620Programs are organized as sets of compilation units or modules. 1621 1622Each module creates its own scope, i.e., any declarations (variables, functions, classes, etc.) declared in the module are not visible outside that module unless they are explicitly exported. 1623 1624Conversely, a variable, function, class, interface, etc. exported from another module must first be imported to a module. 1625 1626### Export 1627 1628A top-level declaration can be exported by using the keyword `export`. 1629 1630A declared name that is not exported is considered private and can be used only in the module where it is declared. 1631 1632**NOTE**: Use braces ({}) when importing a declaration that was exported using the keyword `export`. 1633 1634```typescript 1635export class Point { 1636 x: number = 0; 1637 y: number = 0; 1638 constructor(x: number, y: number) { 1639 this.x = x; 1640 this.y = y; 1641 } 1642} 1643export let Origin = new Point(0, 0); 1644export function Distance(p1: Point, p2: Point): number { 1645 return Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y)); 1646} 1647``` 1648 1649### Import 1650 1651#### Static Import 1652 1653Import declarations are used to import entities exported from other modules and provide their bindings in the current module. 1654An import declaration consists of two parts: 1655 1656* Import path that determines the module to import from. 1657* Import bindings that define the set of usable entities in the imported module, and the form of use (i.e., qualified or unqualified use). 1658 1659Import bindings may have several forms. 1660 1661Let's assume a module has the path './utils' and export entities 'X' and 'Y'. 1662 1663An import binding of the form `* as A` binds the name 'A', and all entities exported from the module defined by the import path can be accessed by using the qualified name `A.name`: 1664 1665```typescript 1666import * as Utils from './utils' 1667Utils.X // denotes X from Utils 1668Utils.Y // denotes Y from Utils 1669``` 1670 1671An import binding of the form `{ ident1, ..., identN }` binds an exported entity with a specified name, which can be used as a simple name: 1672 1673```typescript 1674import { X, Y } from './utils' 1675X // denotes X from Utils 1676Y // denotes Y from Utils 1677``` 1678 1679If a list of identifiers contains aliasing of the form `ident as alias`, then entity `ident` is bound under the name `alias`: 1680 1681```typescript 1682import { X as Z, Y } from './utils' 1683Z // denotes X from Utils 1684Y // denotes Y from Utils 1685X // Compile-time error: 'X' is not visible 1686``` 1687#### Dynamic Import 1688Unlike static import, static import allows you to load a module conditionally or on demand. 1689The **import() **syntax, commonly called dynamic import, is a function-like expression that allows for dynamic loading of a module. It returns a promise. 1690In the following example, **import(modulePath)** loads the module and returns a promise that resolves into a module object that contains all its exports. This expression can be called from any place in the code. 1691 1692```typescript 1693let modulePath = prompt("Which module to load?"); 1694import(modulePath) 1695.then(obj => <module object>) 1696.catch(err => <loading error, e.g. if no such module>) 1697``` 1698 1699You can also use **let module = await import(modulePath)** inside an async function. 1700 1701```typescript 1702// say.ts 1703export function hi() { 1704 console.log('Hello'); 1705} 1706export function bye() { 1707 console.log('Bye'); 1708} 1709``` 1710 1711Then dynamic import can be like this: 1712 1713```typescript 1714async function test() { 1715 let ns = await import('./say'); 1716 let hi = ns.hi; 1717 let bye = ns.bye; 1718 hi(); 1719 bye(); 1720} 1721``` 1722 1723For more details about dynamic import, see [Dynamic Import](arkts-dynamic-import.md). 1724 1725<!--RP1--><!--RP1End--> 1726 1727### Top-Level Statements 1728 1729A module can contain any statements at the module level, except `return` ones. 1730 1731## Keywords 1732 1733### this 1734 1735The keyword `this` can only be used in instance methods of a class. 1736 1737**Example** 1738 1739```typescript 1740class A { 1741 count: string = 'a'; 1742 m(i: string): void { 1743 this.count = i; 1744 } 1745} 1746``` 1747 1748Constraints: 1749 1750* Type notation using `this` is not supported. 1751* Using `this` inside standalone functions is not supported. 1752 1753**Example** 1754 1755```typescript 1756class A { 1757 n: number = 0; 1758 f1(arg1: this) {} // Compile-time error. Type notation using this is not supported. 1759 static f2(arg1: number) { 1760 this.n = arg1; // Compile-time error. Using this inside standalone functions is not supported. 1761 } 1762} 1763 1764function foo(arg1: number) { 1765 this.n = i; // Compile-time error. Using this inside standalone functions is not supported. 1766} 1767``` 1768 1769The keyword `this` used as a primary expression denotes a value that is a reference to the following: 1770 1771* Object for which the instance method is called; or 1772* Object being constructed. 1773 1774The value denoted by `this` in a lambda body and in the surrounding context is the same. 1775 1776## Support for ArkUI 1777 1778This section demonstrates mechanisms that ArkTS provides for creating graphical user interface (GUI) programs. The section is based on the ArkUI declarative framework. ArkUI provides a set of extensions of the standard TypeScript to declaratively describe the GUI of the applications and the interaction between the GUI components. 1779 1780### ArkUI Example 1781 1782The [Example](arkts-mvvm.md#example) provides a complete ArkUI-based application as an illustration of GUI programming capabilities. 1783 1784For more details of the ArkUI features, refer to the ArkUI [Basic Syntax](arkts-basic-syntax-overview.md). 1785