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