1e41f4b71Sopenharmony_ci# ArkTS Migration Background
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ciThis chapter explains why it makes sense to migrate from the standard TypeScript to ArkTS. In general, there are two reasons for doing this:
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ci## Program Stability
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciDynamically typed languages like JavaScript are very good at allowing programs to write code fast. At the same time, these languages are
8e41f4b71Sopenharmony_cinotorious for unexpected runtime errors. For example, a developer may forget to check some value for `undefined`, and as a result of this, the program may crash, which causes inconvenience to the users. Detecting such issues during development time would be much more beneficial. TypeScript helps greatly here: It allows to annotate the code with types, and many errors will be detected by the compiler, prior to deployment and usage of the code. However, even TypeScript has limitations and sometimes permits to annotate the code with types “loosely”, which still leaves a gap for runtime errors. ArkTS tries to overcome this drawback: It enforces static typing for even stricter type checking and less runtime errors.
9e41f4b71Sopenharmony_ci
10e41f4b71Sopenharmony_ciThe following case demonstrates how we can improve stability and correctness of our code by enforcing stricter type checking in ArkTS.
11e41f4b71Sopenharmony_ci
12e41f4b71Sopenharmony_ci
13e41f4b71Sopenharmony_ci**Explicit Initialization of Fields for Better Stability**
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ciArkTS 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.
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ciLet’s take a look at the following TypeScript code:
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ci```typescript
20e41f4b71Sopenharmony_ciclass Person {
21e41f4b71Sopenharmony_ci  name: string // undefined
22e41f4b71Sopenharmony_ci  
23e41f4b71Sopenharmony_ci  setName(n: string): void {
24e41f4b71Sopenharmony_ci    this.name = n
25e41f4b71Sopenharmony_ci  }
26e41f4b71Sopenharmony_ci  
27e41f4b71Sopenharmony_ci  getName(): string {
28e41f4b71Sopenharmony_ci  // Return type "string" hides from the developers the fact that name can be undefined.
29e41f4b71Sopenharmony_ci  // The most correct would be to write the return type as "string | undefined". By doing so
30e41f4b71Sopenharmony_ci  // we tell the users of our API about all possible return values.
31e41f4b71Sopenharmony_ci    return this.name
32e41f4b71Sopenharmony_ci  }
33e41f4b71Sopenharmony_ci}
34e41f4b71Sopenharmony_ci
35e41f4b71Sopenharmony_cilet buddy = new Person()
36e41f4b71Sopenharmony_ci// Let's assume that the developer forgets to call setName:
37e41f4b71Sopenharmony_ci// buddy.setName("John")
38e41f4b71Sopenharmony_cibuddy.getName().length; // runtime exception: name is undefined
39e41f4b71Sopenharmony_ci```
40e41f4b71Sopenharmony_ci
41e41f4b71Sopenharmony_ciSince ArkTS requires explicit initialization, the code looks like this:
42e41f4b71Sopenharmony_ci
43e41f4b71Sopenharmony_ci```typescript
44e41f4b71Sopenharmony_ciclass Person {
45e41f4b71Sopenharmony_ci  name: string = ''
46e41f4b71Sopenharmony_ci  
47e41f4b71Sopenharmony_ci  setName(n: string): void {
48e41f4b71Sopenharmony_ci    this.name = n
49e41f4b71Sopenharmony_ci  }
50e41f4b71Sopenharmony_ci  
51e41f4b71Sopenharmony_ci  // The type is string in all cases, null and undefined are impossible.
52e41f4b71Sopenharmony_ci  getName(): string {
53e41f4b71Sopenharmony_ci    return this.name
54e41f4b71Sopenharmony_ci  }
55e41f4b71Sopenharmony_ci}
56e41f4b71Sopenharmony_ci
57e41f4b71Sopenharmony_cilet buddy = new Person()
58e41f4b71Sopenharmony_ci// Let's assume that the developer forgets to call setName:
59e41f4b71Sopenharmony_ci// buddys.setName("John")
60e41f4b71Sopenharmony_cibuddy.getName().length; // 0, no runtime error
61e41f4b71Sopenharmony_ci```
62e41f4b71Sopenharmony_ci
63e41f4b71Sopenharmony_ciIf `name` can be `undefined`, this is also should be specified explicitly:
64e41f4b71Sopenharmony_ci
65e41f4b71Sopenharmony_ci```typescript
66e41f4b71Sopenharmony_ciclass Person {
67e41f4b71Sopenharmony_ci    name ?: string // The field may be undefined
68e41f4b71Sopenharmony_ci
69e41f4b71Sopenharmony_ci    setName(n: string): void {
70e41f4b71Sopenharmony_ci        this.name = n
71e41f4b71Sopenharmony_ci    }
72e41f4b71Sopenharmony_ci
73e41f4b71Sopenharmony_ci    // Compile-time error:
74e41f4b71Sopenharmony_ci    // name can be "undefined", so we cannot say to those who use this API
75e41f4b71Sopenharmony_ci    // that it returns only strings:
76e41f4b71Sopenharmony_ci    getNameWrong(): string {
77e41f4b71Sopenharmony_ci        return this.name
78e41f4b71Sopenharmony_ci    }
79e41f4b71Sopenharmony_ci
80e41f4b71Sopenharmony_ci    getName(): string | undefined { // Return type matches the type of name
81e41f4b71Sopenharmony_ci        return this.name
82e41f4b71Sopenharmony_ci    }
83e41f4b71Sopenharmony_ci}
84e41f4b71Sopenharmony_ci
85e41f4b71Sopenharmony_cilet buddy = new Person()
86e41f4b71Sopenharmony_ci// Let's assume that the developer forgets to call setName:
87e41f4b71Sopenharmony_ci// buddy.setName("John")
88e41f4b71Sopenharmony_ci
89e41f4b71Sopenharmony_ci// Compile-time(!) error: Compiler suspects that we
90e41f4b71Sopenharmony_ci// may possibly access something undefined and won't build the code:
91e41f4b71Sopenharmony_cibuddy.getName().length; // The code won't build and run
92e41f4b71Sopenharmony_ci
93e41f4b71Sopenharmony_cibuddy.getName()?.length; // Builds ok, no runtime error
94e41f4b71Sopenharmony_ci```
95e41f4b71Sopenharmony_ci
96e41f4b71Sopenharmony_ci
97e41f4b71Sopenharmony_ci
98e41f4b71Sopenharmony_ci## Program Performance
99e41f4b71Sopenharmony_ci
100e41f4b71Sopenharmony_ciTo ensure correctness of the program, dynamically languages have to check actual types of objects when the program actually runs. Back to our example, JavaScript does not allow to read a property from `undefined`. But the only way to check if some value is `undefined` is to perform a runtime check, that all JavaScript engines do: if the value is not `undefined`, the property is read, otherwise an exception is thrown. Modern engines can optimize such checks greatly, but these checks cannot be eliminated completely, which leads to code slowdown. Since the standard TypeScript compiles to JavaScript, the code written in TypeScript has exactly the same issues as described above. ArkTS addresses this problem. Since static typing is enforced, ArkTS compiles the program not to JavaScript, but to ARK bytecode, which is faster to execute and easier to optimize even further.
101e41f4b71Sopenharmony_ci
102e41f4b71Sopenharmony_ci
103e41f4b71Sopenharmony_ci**Null Safety**
104e41f4b71Sopenharmony_ci
105e41f4b71Sopenharmony_ciLet’s take a look at the following code:
106e41f4b71Sopenharmony_ci
107e41f4b71Sopenharmony_ci```typescript
108e41f4b71Sopenharmony_cifunction notify(who: string, what: string) {
109e41f4b71Sopenharmony_ci  console.log(`Dear ${who}, a message for you: ${what}`)
110e41f4b71Sopenharmony_ci}
111e41f4b71Sopenharmony_ci
112e41f4b71Sopenharmony_cinotify('Jack', 'You look great today')
113e41f4b71Sopenharmony_ci```
114e41f4b71Sopenharmony_ci
115e41f4b71Sopenharmony_ciIn most cases, the `notify` function will take two string variables as an input and produces a new string. However, what if we pass some “special” values to the function, for example `notify(null, undefined)`? The program will continue to work, the output will be as expected (`Dear null, a message for you: undefined`), so from the first glance everything is fine. But please note that the engine that runs our code should always check for such special cases to ensure correct behavior. In pseudocode, something like this happens:
116e41f4b71Sopenharmony_ci
117e41f4b71Sopenharmony_ci```typescript
118e41f4b71Sopenharmony_cifunction __internal_tostring(s: any): string {
119e41f4b71Sopenharmony_ci  if (typeof s === 'string')
120e41f4b71Sopenharmony_ci    return s
121e41f4b71Sopenharmony_ci  if (s === undefined)
122e41f4b71Sopenharmony_ci    return 'undefined'
123e41f4b71Sopenharmony_ci  if (s === null)
124e41f4b71Sopenharmony_ci    return 'null'
125e41f4b71Sopenharmony_ci  // ...
126e41f4b71Sopenharmony_ci}
127e41f4b71Sopenharmony_ci```
128e41f4b71Sopenharmony_ci
129e41f4b71Sopenharmony_ciNow imagine that our `notify` function is a part of some complex heavy-loaded system which sends real notifications instead of just writing to the log. In
130e41f4b71Sopenharmony_cithis scenario, executing all these checks from our `__internal_tostring` function may turn into a performance problem.
131e41f4b71Sopenharmony_ci
132e41f4b71Sopenharmony_ciBut what if we could somehow guarantee to our exectuion engine that the only values that are passed to the `notify` function are “real” strings, but not
133e41f4b71Sopenharmony_cisome “special” values like `null` or `undefined`? In this case, checks like `__internal_tostring` become redundant because when we execute the program
134e41f4b71Sopenharmony_ciwe are 100% sure that there will be no corner cases. For this particular case this mechanism would be called “null-safety”, i.e. guarantee that `null` is
135e41f4b71Sopenharmony_cinot a valid value of the `string` type. If we had such feature, the code would not simply build:
136e41f4b71Sopenharmony_ci
137e41f4b71Sopenharmony_ci```typescript
138e41f4b71Sopenharmony_cifunction notify(who: string, what: string) {
139e41f4b71Sopenharmony_ci  console.log(`Dear ${who}, a message for you: ${what}`)
140e41f4b71Sopenharmony_ci}
141e41f4b71Sopenharmony_ci
142e41f4b71Sopenharmony_cinotify('Jack', 'You look great today')
143e41f4b71Sopenharmony_cinotify(null, undefined) // Compile-time error
144e41f4b71Sopenharmony_ci```
145e41f4b71Sopenharmony_ci
146e41f4b71Sopenharmony_ciIn TypeScript such behavior can be turned on by a special compiler flag called `strictNullChecks`. But since the standard TypeScript is compiled to JavaScript, which does not have such feature, “strict null checks” work only in compile-time, for better type checking. However, ArkTS considers null-safety a very
147e41f4b71Sopenharmony_ciimportant feature from both stability and performance points of view. That’s why it is enforced in the language and the example above always produces
148e41f4b71Sopenharmony_cicompile-time errors. In exchange, we give our running engine much more information and guarantees about possible type values, which helps better optimize performance.
149e41f4b71Sopenharmony_ci
150e41f4b71Sopenharmony_ci## .ets Code Compatibility
151e41f4b71Sopenharmony_ci
152e41f4b71Sopenharmony_ciPrior to API version 10, ArkTS (.ets file) completely adopted the syntax of standard TS. Since API version 10, the ArkTS syntax rules are clearly defined based on the preceding design considerations. In addition, the SDK adds the ArkTS syntax validation for .ets files to the compilation process, and prompts you to adapt to the new ArkTS syntax through warnings or errors.
153e41f4b71Sopenharmony_ci
154e41f4b71Sopenharmony_ciSyntax issues are classified as warning or error, depending on the **compatibleSdkVersion** of the project:
155e41f4b71Sopenharmony_ci
156e41f4b71Sopenharmony_ci  - In compatible mode, where the value of **compatibleSdkVersion** is greater than or equal to 10, syntax issues are reported as errors and will block the compilation process. The compilation can be successful only after the ArkTS syntax is fully adapted.
157e41f4b71Sopenharmony_ci  - In compatible mode, where the value of **compatibleSdkVersion** is smaller than 10, syntax issues are reported as warnings and will not block the compilation process.
158e41f4b71Sopenharmony_ci
159e41f4b71Sopenharmony_ci
160e41f4b71Sopenharmony_ci## ArkCompiler Runtime Compatibility with TS/JS
161e41f4b71Sopenharmony_ci
162e41f4b71Sopenharmony_ciThe OpenHarmony SDK of API version 11 uses TypeScript 4.9.5, with the **target** field of **es2017**. In the application, you can use the syntax of ECMA2017+ for TS/JS development.
163e41f4b71Sopenharmony_ci
164e41f4b71Sopenharmony_ci**Application Environment Restrictions**
165e41f4b71Sopenharmony_ci
166e41f4b71Sopenharmony_ci1. Force the use of strict mode (use strict)
167e41f4b71Sopenharmony_ci2. Prohibit the use of `eval()`
168e41f4b71Sopenharmony_ci3. Prohibit the use of `with() {}`
169e41f4b71Sopenharmony_ci4. Prohibit creating functions with strings as code
170e41f4b71Sopenharmony_ci
171e41f4b71Sopenharmony_ci**Differences from Standard TS/JS**
172e41f4b71Sopenharmony_ci
173e41f4b71Sopenharmony_ciIn standard TS/JS, the number format of JSON, the decimal point must be followed by a number. Scientific notation such as `2.e3` is not allowed and throws `SyntaxError`. In the ArkCompiler Runtime, this type of scientific notation is allowed.
174