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