ArkTS is the preferred main programming language for application development in OpenHarmony. ArkTS is a superset of [TypeScript](https://www.typescriptlang.org/)(TS for short). It contains all TS features and added features. Before getting started with ArkTS, it would be helpful if you have experience with TS development.
ArkTS is the preferred main programming language for application development in OpenHarmony. ArkTS maintains the basic style of [TypeScript](https://www.typescriptlang.org/)(TS for short). It is a static typing language. Some TS features are restricted for better performance.
The added features offered by ArkTS include the following:
The following syntaxes in TS are restricted in ArkTS:
- Static typing is enforced. Static typing is one of the most important features of ArkTS. If the program is statically typed, i.e. all types are known at the compile time, it’s much easier to understand which data structures are used in the code. At the same time, since all types are known before the program actually runs, code correctness can be verified by the compiler, which eliminates many runtime type checks and improves the performance.
- Changing object layout in runtime is prohibited. To achieve maximum performance benefits, ArkTS requires that layout of objects does not change during program execution.
- Semantics of operators is restricted. To achieve better performance and encourage developers to write cleaner code, ArkTS restricts the semantics of operators. Such as, the binary `+` operator supports only for strings and numbers but not for objects.
- structural typing is not supported. Support for structural typing is a major feature which needs lots of consideration and careful implementation in language specification, compiler and runtime. Currently, ArkTS does not supports structural typing. The team will be ready to reconsider based on real-world scenarios and feedback.
The added features offered by ArkTS for ArkUI framework include the following:
-[Basic syntax](arkts-basic-syntax-overview.md): ArkTS defines declarative UI description, custom components, and dynamic extension of UI elements. All these, together with built-in components, event methods, and attribute methods in ArkUI, jointly underpin UI development.
-[Basic syntax](arkts-basic-syntax-overview.md): ArkTS defines declarative UI description, custom components, and dynamic extension of UI elements. All these, together with built-in components, event methods, and attribute methods in ArkUI, jointly underpin UI development.
| `a & b` | Bitwise AND: sets each bit to 1 if the corresponding bits of both operands are 1, otherwise to 0. |
| `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. |
| `a ^ b` | Bitwise XOR: sets each bit to 1 if the corresponding bits of both operands are different, otherwise to 0. |
| `~ a` | Bitwise NOT: inverts the bits of the operand. |
| `a << b` | Shift left: shifts the binary representation of *a* to the left by *b* bits. |
| `a >> b` | Arithmetic right shift: shifts the binary representation of *a* to the right by *b* bits with sign-extension. |
| `a >>> b` | Logical right shift: shifts the binary representation of *a* to the right by *b* bits with zero-extension. |
### Logical Operators
| Operator | Description |
|------------|---------------|
| `a && b` | logical AND |
| `a \|\| b` | logical OR |
| `! a` | logical NOT |
## Control Flow
### `If` Statements
Use `if` statement to execute a sequence of statements when a logical
condition is true, or another set of statements (if provided) otherwise.
`else` part may contain more `if` statements as well.
The `if` statement looks as follows:
```typescript
if(condition1){
// statements1
}elseif(condition2){
// statements2
}else{
// else_statements
}
```
All conditional expressions should be of the type `boolean` or other types
(`string`, `number`, etc.). For types other than `boolean`, implicit
conversion rules apply:
```typescript
lets1="Hello"
if(s1){
console.log(s1)// prints "Hello"
}
lets2="World"
if(s2.length!=0){
console.log(s2)// prints "World"
}
```
### `Switch` Statements
Use `switch` statement to execute a sequence of statements that match the
value of the switch expression.
The `switch` statement looks as follows:
```typescript
switch(expression){
caselabel1:// will be executed if label1 is matched
// ...
// statements1
// ...
break;// Can be omitted
caselabel2:
caselabel3:// will be executed if label2 or label3 is matched
// ...
// statements23
// ...
break;// Can be omitted
default:
// default_statements
}
```
The `switch` expression type must be of `number`, `enum` or `string`
type.
Each label must be either a constant expression or the name of an enum constant.
If the value of a `switch` expression equals the value of some label, then
the corresponding statements are executed.
If there is no match, and the `switch` has the default clause, then the
default statements are executed.
An optional `break` statement allows to break out of the `switch` and
continue executing the statement that follows the `switch`.
If there is no break, then the next statements in the `switch` is executed.
### Conditional Expressions
The conditional expression `?` : uses the `boolean` value of the first
expression to decide which of two other expressions to evaluate.
It looks as follows:
```typescript
condition?expression1:expression2
```
The 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.
Example:
```typescript
letisValid=Math.random()>0.5?true:false
letmessage=isValid?'Valid':'Failed'
```
### `For` Statements
A `for` statement is executed repeatedly until the specified loop exit condition
is `false`. A `for` statement looks as follows:
```typescript
for([init];[condition];[update]){
statements
}
```
When a `for` statement is executed, the following process takes place:
1. An `init` expression is executed, if any. This expression usually initializes one or more loop counters.
2. 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`, the `for` loop terminates.
3. The statements of the `for` body are executed.
4. If there is an `update` expression, the `update` expression is executed.
5. Go back to step 2.
Example:
```typescript
letsum=0
for(leti=0;i<10;i+=2){
sum+=i
}
```
### `For-of` Statements
Use `for-of` statements to iterate over an array or string. A `for-of`
statement looks as follows:
```typescript
for(forVarofexpression){
statements
}
```
Example:
```typescript
for(letchof"a string object"){/* process ch */}
```
### `While` Statements
A `while` statement has its body statements executed as long as the specified condition
evaluates to `true`. It looks as follows:
```typescript
while(condition){
statements
}
```
The condition must be a logical expression.
Example:
```typescript
letn=0
letx=0
while(n<3){
n++
x+=n
}
```
### `Do-while` Statements
The `do-while` statements are executed repetitively until the specified
condition evaluates to false. It looks as follows:
```typescript
do{
statements
}while(condition)
```
The condition must be a logical expression.
Example:
```typescript
leti=0
do{
i+=1
}while(i<10)
```
### `Break` Statements
Use a `break` statement to terminate any `loop` statement or `switch`.
Example:
```typescript
letx=0
while(true){
x++;
if(x>5){
break;
}
}
```
A `break` statement with a label identifier transfers control out of the
enclosing statement to the one which has the same label identifier.
Example:
```typescript
letx=1
label:while(true){
switch(x){
case1:
// statements
breaklabel// breaks the while
}
}
```
### `Continue` Statements
A `continue` statement stops the execution of the current loop iteration and
passes control to the next iteration.
Example:
```typescript
letsum=0
for(letx=0;x<100;x++){
if(x%2==0){
continue
}
sum+=x
}
```
### `Throw` and `Try` Statements
A `throw` statement is used to throw an exception or error:
```typescript
thrownewError("this error")
```
A `try` statement is used to catch and handle an exception or error:
```typescript
try{
// try block
}catch(e){
// handle the situation
}
```
The example below shows the `throw` and `try` statements used to handle
A function declaration introduces a named function, specifying its name,
parameters, return type and body.
Below is a simple function with two string parameters and string return type:
```typescript
functionadd(x:string,y:string):string{
letz:string=`${x}${y}`
returnz
}
```
For every parameter its type annotation must be specified.
An optional parameter allows to omit the corresponding argument when
calling a function. The last parameter of a function can be a rest parameter.
## Optional Parameters
An optional parameter has the form `name?: Type`.
```typescript
functionhello(name?:string){
if(name==undefined){
console.log("Hello, ${name}!")
}else{
console.log("Hello!")
}
}
```
Another form contains an expression that specifies a default value.
If the corresponding argument to such parameter is omitted in a function call,
then this parameter has the default value.
```typescript
functionmultiply(n:number,coeff:number=2):number{
returnn*coeff
}
multiply(2)// returns 2*2
multiply(2,3)// returns 2*3
```
## The Rest Parameter
The last parameter of a function can be a rest parameter.
It allows functions or methods to take unlimited number of arguments.
```typescript
functionsum(...numbers:number[]):number{
letres=0
for(letnofnumbers)
res+=n
returnres
}
sum()// returns 0
sum(1,2,3)// returns 6
```
## Return Types
If function return type can be inferred from its body content then it can be omitted from the function declaration.
```typescript
// Explicit return type
functionfoo():string{return"foo"}
// Implicit return type inferred as string
functiongoo(){return"goo"}
```
The return type of a function that does not need to return a value may be explicitly specified as `void` or omitted altogether. No return statement is needed for such functions.
Both notations below are valid:
```typescript
functionhi1(){console.log("hi")}
functionhi2():void{console.log("hi")}
```
## Function Scope
Variables and other entities defined in a function are local to the function and cannot be accessed outside.
If 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 outer entity.
## Function Calls
Calling a function actually leads to its body execution while arguments of the call are assigned to function parameters.
If the function is defined as follows:
```typescript
functionjoin(x:string,y:string):string{
letz:string=`${x}${y}`
returnz
}
```
then it is called with two arguments of the type `string`:
```typescript
letx=join("hello","world")
console.log(x)
```
## Function Types
Function types are commonly used as follows to define callbacks:
```typescript
typetrigFunc=(x:number)=>number// this is a function type
functiondo_action(f:trigFunc){
f(3.141592653589)// call the function
}
do_action(Math.sin)// pass the function as the parameter
```
## Arrow Functions or Lambdas
A function can be defined as an arrow function, for example:
```typescript
letsum=(x:number,y:number):number=>{
returnx+y
}
```
An arrow function return type may be omitted; in this case it is inferred from the function body.
An expression can be specified as an arrow function, making notation shorter, so the following two notations are equivalent:
```typescript
letsum1=(x:number,y:number)=>{returnx+y}
letsum2=(x:number,y:number)=>x+y
```
## Closure
An arrow function is usually defined inside another function. As an inner function, it can access all variables and functions defined in the outer functions.
To capture the context, an inner function forms a closure of its environment.
The closure allows accessing such inner function outside its own environment.
```typescript
functionf():()=>number{
letcount=0
return():number=>{count++;returncount}
}
letz=f()
console.log(z())// output: 1
console.log(z())// output: 2
```
In the sample above, the arrow function closure captures the `count` variable.
## Function Overload Signatures
A function can be specified to be called in different ways by writing overload signatures. To do so, several functions headers are written that they have the same name but different signatures, immediately followed by the single implementing function.
The extended class inherits fields and methods from the base class, but not constructors, and can add its own fields and methods as well as override methods defined by the base class.
The base class is also called ‘parent class’ or ‘superclass’. The extended class also called ‘derived class’ or ‘subclass’.
Example:
```typescript
classPerson{
name:string=""
private_age=0
getage():number{
returnthis._age
}
}
classEmployeeextendsPerson{
salary:number=0
calculateTaxes():number{
returnthis.salary*0.42
}
}
```
A class containing the `implements` clause must implement all methods defined in all listed interfaces, except the methods defined with default implementation.
```typescript
interfaceDateInterface{
now():string;
}
classMyDateimplementsDateInterface{
now():string{
// implementation is here
return"now is now"
}
}
```
### Access to Super
The keyword `super` can be used to access instance fields, instance methods and constructors from the super class.
It is often used to extend basic functionality of subclass with the required behavior taken from the super class:
```typescript
classRectangle{
protectedheight:number=0
protectedwidth:number=0
constructor(h:number,w:number){
this.height=h
this.width=w
}
draw(){
/* draw bounds */
}
}
classFilledRectangleextendsRectangle{
color=""
constructor(h:number,w:number,c:string){
super(h,w)// call of super constructor
this.color=c
}
overridedraw(){
super.draw()// call of super methods
// super.height - can be used here
/* fill rectangle */
}
}
```
### Override Methods
A subclass may override implementation of a method defined in its superclass.
An overridden method may be marked with the keyword `override`, to improve readability.
An overridden method must have the same types of parameters and same or derived return type as the original method.
```typescript
classRectangle{
// ...
area():number{
// implementation
return0
}
}
classSquareextendsRectangle{
privateside:number=0
overridearea():number{
returnthis.side*this.side
}
}
```
### Method Overload Signatures
A method can be specified to can be called in different ways by writing overload signatures. To do so, several method headers are written that have the same name but different signatures, immediately followed by the single implementation method.
It is an error if two overload signatures have the same name and identical parameter lists.
## Constructors
A class declaration may contain a constructor that is used to initialize object state.
Constructor is defined as follows:
```typescript
constructor([parameters]){
// ...
}
```
If no constructor is defined, then a default constructor with an empty parameter list is created automatically, for example:
```typescript
classPoint{
x:number=0
y:number=0
}
letp=newPoint()
```
In this case the default constructor fills the instance fields with default values for the field types.
### Constructors in Derived Class
The first statement of a constructor body can use the keyword `super` to explicitly call a constructor of the direct superclass.
```typescript
classRectangle{
constructor(width:number,height:number){
// ...
}
}
classSquareextendsRectangle{
constructor(side:number){
super(side,side)
}
}
```
If 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()`.
### Constructor Overload Signatures
A constructor can be specified to can be called in different ways by writing overload signatures. To do so, several constructor headers are written that have the same name but different signatures, immediately followed by the single implementation constructor.
It is an error if two overload signatures have the same name and identical parameter lists.
## Visibility Modifiers
Both methods and properties of a class can have visibility modifiers.
There are several visibility modifiers: `private`, `protected`,
`public`, and `internal`. The default visibility is `public`.
`internal` allows to limit visibility within the current package.
### Public Visibility
The `public` members (fields, methods, constructors) of a class are visible in any part of the program, where their class is visible.
### Private Visibility
A `private` member cannot be accessed outside the class in which it is declared, for example:
```typescript
classC{
publicx:string=""
privatey:string=""
set_y(new_y:string){
this.y=new_y// ok, as y is accessible within the class itself
}
}
letc=newC()
c.x="a"// ok, the field is public
c.y="b"// compile-time error: 'y' is not visible
```
### Protected Visibility
The `protected` modifier acts much like the `private` modifier, but
`protected` members are also accessible in derived classes, for example:
```typescript
classBase{
protectedx:string=""
privatey:string=""
}
classDerivedextendsBase{
foo(){
this.x="a"// ok, access to protected member
this.y="b"// compile-time error, 'y' is not visible, as it is private
}
}
```
## Object Literals
An 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 `new` expression as it is more convenient in some cases.
A class composite is written as a comma-separated list of name-value pairs enclosed in ‘{’ and ‘}’.
```typescript
classC{
n:number=0
s:string=""
}
letc:C={n:42,s:"foo"}
```
Due to static typing of the ArkTS the object literals can be used in context where the class or interface type of the object literal can be inferred as in the example above. Other valid cases:
```typescript
classC{
n:number=0
s:string=""
}
functionfoo(c:C){}
letc:C
c={n:42,s:"foo"}// type of the variable is used
foo({n:42,s:"foo"})// type of the parameter is used
functionbar():C{
return{n:42,s:"foo"}// return type is used
}
```
Type of an array element or a type of a class field also can be used:
```typescript
classC{
n:number=0
s:string=""
}
letcc:C[]=[{n:1,s:"a"},{n:2,s:"b"}]
```
### Object Literals of the Record Type
The generic Record<K,V> type is used to map the properties of a type (Key type) to another type (Value type).
A special form of an object literal is used to initialize the value of such type:
```typescript
letmap:Record<string,number>={
"John":25,
"Mary":21,
}
console.log(map["John"])// prints 25
```
The K type can be either string or number, while V can be any type.
```typescript
interfacePersonInfo{
age:number
salary:number
}
letmap:Record<string,PersonInfo>={
"John":{age:25,salary:10},
"Mary":{age:21,salary:20}
}
```
# Interfaces
An interface declaration introduces a new type. Interfaces are a common way of defining contracts between various part of codes.
Interfaces are used to write polymorphic code, which can be applied to any class instances that implement a particular interface.
An interface usually contains properties and method headers.
Examples:
```typescript
interfaceStyle{
color:string// property
}
interfaceArea{
calculateArea():number// method header
someMethod():void;// method header
}
```
Examples of a class implementing an interface:
```typescript
// Interface:
interfaceArea{
calculateArea():number// method header
someMethod():void;// method header
}
// Implementation:
classRectangleimplementsArea{
privatewidth:number=0
privateheight:number=0
someMethod():void{
console.log("someMethod called")
}
calculateArea():number{
this.someMethod()// calls another method and returns result
returnthis.width*this.height
}
}
```
## Interface Properties
An interface property can be in a form of field, getter, setter or both getter and setter.
A property field is just a shortcut notation of a getter/setter pair, and the following notations are equal:
```typescript
interfaceStyle{
color:string
}
interfaceStyle{
getcolor():string
setcolor(x:string)
}
```
A class that implements an interface may also use a short or a long notation:
```typescript
interfaceStyle{
color:string
}
classStyledRectangleimplementsStyle{
color:string=""
}
```
The short notation implicitly defines a private field and getter and setter:
```typescript
interfaceStyle{
color:string
}
classStyledRectangleimplementsStyle{
private_color:string=""
getcolor():string{returnthis._color}
setcolor(x:string){this._color=x}
}
```
## Interface Inheritance
An interface may extend other interfaces like in the example below:
```typescript
interfaceStyle{
color:string
}
interfaceExtendedStyleextendsStyle{
width:number
}
```
An extended interface contains all properties and methods of the interface it extends and may also add its own properties and methods.
## Interface Visibility Modifiers
Properties and methods are `public`.
Only methods with default implementation may be defined as `private`.
# Generic Types and Functions
Generic types and functions allow creating the code capable to work over a variety of types rather than a single one.
## Generic Classes and Interfaces
A class and an interface can be defined as generics, adding parameters to the type definition, like the type parameter `Element` in the following example:
```typescript
classStack<Element>{
publicpop():Element{
// ...
}
publicpush(e:Element){
// ...
}
}
```
To use type Stack, the type argument must be specified for each type parameter:
```typescript
lets=newStack<string>
s.push("hello")
```
Compiler ensures type safety while working with generic types and functions. See below
```typescript
lets=newStack<string>
s.push(55)// That will be a compile-time error
```
## Generic Constraints
Type parameters of generic types can be bounded. For example, the `Key` type parameter in the `HashMap<Key, Value>` container must have a hash method, i.e., it should be hashable.
```typescript
interfaceHashable{
hash():number
}
classHasMap<KeyextendsHashable,Value>{
publicset(k:Key,v:Value){
leth=k.hash()
// ... other code ...
}
}
```
In the above example, the `Key` type extends `Hashable`, and all methods of `Hashable` interface can be called for keys.
## Generic Functions
Use a generic function to create a more universal code. Consider a function that returns the last element of the array:
```typescript
functionlast(x:number[]):number{
returnx[x.length-1]
}
console.log(last([1,2,3]))// output: 3
```
If the same function needs to be defined for any array, define it as generic with a type parameter:
```typescript
functionlast<T>(x:T[]):T{
returnx[x.length-1]
}
```
Now, the function can be used with any array.
In a function call, type argument may be set explicitly or implicitly:
```typescript
// Explicit type argument
console.log(last<string>(["aa","bb"]))
console.log(last<number>([1,2,3]))
// Implicit type argument:
// Compiler understands the type argument based on the type of the call arguments
console.log(last([1,2,3]))
```
## Generic Defaults
Type parameters of generic types can have defaults.
It allows not specifying the actual type arguments but using just the generic type name.
Example below illustrates this for both classes and functions.
```typescript
classSomeType{}
interfaceInterface<T1=SomeType>{}
classBase<T2=SomeType>{}
classDerived1extendsBaseimplementsInterface{}
// Derived1 is semantically equivalent to Derived2
// such function is semantically equivalent to the call below
foo<number>()
```
# Null Safety
All types in ArkTS by default are non-nullable, so the value of a type cannot be null.
It is similar to TypeScript behavior in strict null checking mode
(`strictNullChecks`), but the rules are stricter, and the there is no `undefined` type in ArkTS.
In the example below, all lines cause a compile-time error:
```typescript
letx:number=null// Compile-time error
lety:string=null// ditto
letz:number[]=null// ditto
```
A variable that can have a null value is defined with a union type `T | null`.
```typescript
letx:number|null=null
x=1// ok
x=null// ok
if(x!=null){/* do something */}
```
## Non-Null Assertion Operator
A postfix operator `!` can be used to assert that its operand is non-null.
If applied to a null value, the operator throws an error. Otherwise, the type of the value is changed from `T | null` to `T`:
```typescript
letx:number|null=1
lety:number
y=x+1// compile time error: cannot add to a nullable value
y=x!+1// ok
```
## Null-Coalescing Operator
The null-coalescing binary operator `??` checks whether the evaluation of the left-hand-side expression is equal to null.
If it is, then the result of the expression is the right-hand-side expression; otherwise, it is the left-hand-side expression.
In other words, `a ?? b` equals the ternary operator `a != null ? a : b`.
In the following example, the method `getNick` returns a nickname if it is set; otherwise, empty string is returned:
```typescript
classPerson{
// ...
nick:string|null=null
getNick():string{
returnthis.nick??""
}
}
```
## Optional Chaining
Optional chaining operator `?.` allows writing code where the evaluation stops of an expression that is partially evaluated to `null`.
```typescript
classPerson{
// ...
spouse:Person|null=null
nick:string|null=null
getSpouseNick():string|null{
returnthis.spouse?.nick
}
}
```
**Note**: that the return type of `getSpouseNick` must be `string | null`, as the method may return null.
An optional chain may be of any length and contain any number of `?.`
operators.
In the following sample, the output is a person’s spouse nickname if the person has a spouse, and the spouse has a nickname.
Otherwise, the output is `null`:
```typescript
letp:Person=...
console.log(p?.spouse?.nick)
```
# Modules
Programs are organized as sets of compilation units or modules.
Each 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.
Conversely, a variable, function, class, interface, etc. exported from another module must first be imported to a module.
## Export
A top-level declaration can be exported by using the keyword `export`.
A declared name that is not exported is considered private and can be used only in the module where it is declared.
Import declarations are used to import entities exported from other modules and provide their bindings in the current module. An import declaration consists of two parts:
* Import path that determines the module to import from;
* Import bindings that define the set of usable entities in the imported module and the form of use i.e., qualified or unqualified use.
Import bindings may have several forms.
Let’s assume a module has the path ‘./utils’ and export entities ‘X’ and ‘Y’.
An 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`:
```typescript
import*asUtilsfrom"./utils"
Utils.X// denotes X from Utils
Utils.Y// denotes Y from Utils
```
An import binding of the form `{ ident1, ..., identN }` binds an exported entity with a specified name, which can be used as a simple name:
```typescript
import{X,Y}from"./utils"
X// denotes X from Utils
Y// denotes Y from Utils
```
If a list of identifiers contains aliasing of the form `ident as alias`, then entity `ident` is bound under the name `alias`:
```typescript
import{XasZ,Y}from"./utils"
Z// denotes X from Utils
Y// denotes Y from Utils
X// Compile-time error: 'X' is not visible
```
## Top-Level Statements
A module can contain any statements at the module level, except `return` ones.
If 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.
Otherwise, they are executed before execution of any other function of the module.
## Program Entry Point
An entry point of a program (application) is the top-level `main` function. The `main` function should have either an empty parameter list or a single parameter of `string[]` type.
```typescript
functionmain(){
console.log("this is the program entry")
}
```
# Support for ArkUI
This 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.
## ArkUI Example
The following example provides a complete ArkUI-based application as an
illustration of GUI programming capabilities. For more details about ArkUI