1# ArkTS Migration Background 2 3This chapter explains why it makes sense to migrate from the standard TypeScript to 4ArkTS. In general, there are two reasons for doing this: 5 6- Program stability. Dynamically typed languages like JavaScript are very good at 7 allowing programs to write code fast. At the same time, these languages are 8 notorious for unexpected runtime errors. For example, a developer may forget 9 to check some value for `undefined`, and as a result of this, the program 10 may crash, which causes inconvenience to the users. Detecting such issues 11 during development time would be much more beneficial. TypeScript helps greatly 12 here: It allows to annotate the code with types, and many errors will be 13 detected by the compiler, prior to deployment and usage of the code. 14 However, even TypeScript has limitations and sometimes permits to annotate the code 15 with types “loosely”, which still leaves a gap for runtime errors. ArkTS 16 tries to overcome this drawback: It enforces static typing for even stricter 17 type checking and less runtime errors. 18- Program performance. To ensure correctness of the program, dynamically 19 languages have to check actual types of objects when the program actually 20 runs. Back to our example, JavaScript does not allow to read a property from 21 `undefined`. But the only way to check if some value is `undefined` is to 22 perform a runtime check, that all JavaScript engines do: if the value is not 23 `undefined`, the property is read, otherwise an exception is thrown. Modern 24 engines can optimize such checks greatly, but these checks cannot be 25 eliminated completely, which leads to code slowdown. Since the standard TypeScript 26 compiles to JavaScript, the code written in TypeScript has exactly the same issues as 27 described above. ArkTS addresses this problem. Since static typing is 28 enforced, ArkTS compiles the program not to JavaScript, but to some special 29 execution format called bytecode, which is faster to execute and easier to 30 optimize even further. 31 32Below there are a couple of examples that try to explain how ArkTS can help 33improve program stability and performance. 34 35**Explicit Initialization of Fields for Better Stability** 36 37ArkTS requires that all fields are explicitly initialized with some values 38either when the field is declared or in the `constructor`. This is similar 39to `strictPropertyInitialization` mode of the standard TypeScript. 40 41Let’s take a look at the following TypeScript code: 42 43```typescript 44class Person { 45 name: string // Automatically is set to undefined 46 47 setName(n:string): void { 48 this.name = n 49 } 50 51 getName(): string { 52 // Return type "string" hides from the developers the fact 53 // that name can be undefined. The most correct would be 54 // to write the return type as "string | undefined". By doing so 55 // we tell the users of our API about all possible return values. 56 return this.name 57 } 58} 59 60let buddy = new Person() 61// Let's assume that the developer forgets to call setName: 62// buddy.setName("John") 63buddy.getName().length; // runtime exception: name is undefined 64``` 65 66Since ArkTS requires explicit initialization, the code looks like this: 67 68```typescript 69class Person { 70 name: string = "" // The field always is defined 71 72 setName(n:string): void { 73 this.name = n 74 } 75 76 // The type is string in all cases, null and undefined are impossible. 77 getName(): string { 78 return this.name 79 } 80} 81 82let buddy = new Person() 83// Let's assume that the developer forgets to call setName: 84// buddys.setName("John") 85buddy.getName().length; // 0, no runtime error 86``` 87 88If `name` can be `undefined`, this is also should be specified explicitly: 89 90```typescript 91class Person { 92 name ?: string // The field may be undefined 93 94 setName(n:string): void { 95 this.name = n 96 } 97 98 // Compile-time error: 99 // name can be "undefined", so we cannot say to those who use this API 100 // that it returns only strings: 101 getNameWrong(): string { 102 return this.name 103 } 104 105 getName(): string | undefined { // Return type matches the type of name 106 return this.name 107 } 108} 109 110let buddy = new Person() 111// Let's assume that the developer forgets to call setName: 112// buddy.setName("John") 113 114// Compile-time(!) error: Compiler suspects that we 115// may possibly access something undefined and won't build the code: 116buddy.getName().length; // The code won't build and run 117 118buddy.getName()?.length; // Builds ok, no runtime error 119``` 120 121This case demonstrates how we can improve stability and correctness of our 122code by enforcing stricter type checking in ArkTS. 123 124**Null Safety for Better Performance** 125 126Let’s take a look at the following code: 127 128```typescript 129function notify(who: string, what: string) { 130 console.log(`Dear ${who}, a message for you: ${what}`) 131} 132 133notify("Jack", "You look great today") 134``` 135 136In most cases, the `notify` function will take two string variables as 137an input and produces a new string. However, what if we pass some “special” 138values to the function, for example `notify(null, undefined)`? The program 139will continue to work, the output will be as expected 140(`Dear undefined, a message for you: null`), so from the first glance 141everything is fine. But please note that the engine that runs our code 142should always check for such special cases to ensure correct behavior. In 143pseudocode, something like this happens: 144 145```typescript 146function __internal_tostring(s: any): string { 147 if (typeof s === "string") 148 return s 149 if (s === undefined) 150 return "undefined" 151 if (s === null) 152 return "null" 153 // ... 154} 155``` 156 157Now imagine that our `notify` function is a part of some complex heavy-loaded 158system which sends real notifications instead of just writing to the log. In 159this scenario, executing all these checks from our `__internal_tostring` 160function may turn into a performance problem. 161 162But what if we could somehow guarantee to our exectuion engine that the only 163values that are passed to the `notify` function are “real” strings, but not 164some “special” values like `null` or `undefined`? In this case, checks like 165`__internal_tostring` become redundant because when we execute the program 166we are 100% sure that there will be no corner cases. For this particular case 167this mechanism would be called “null-safety”, i.e. guarantee that `null` is 168not a valid value of the `string` type. If we had such feature, the code 169would not simply build: 170 171```typescript 172function notify(who: string, what: string) { 173 console.log(`Dear ${who}, a message for you: ${what}`) 174} 175 176notify("Jack", "You look great today") 177notify(null, undefined) // Compile-time error 178``` 179 180In TypeScript such behavior can be turned on by a special compiler flag called 181`strictNullChecks`. But since the standard TypeScript is compiled to JavaScript, which 182does not have such feature, “strict null checks” work only in compile-time, 183for better type checking. However, ArkTS considers null-safety a very 184important feature from both stability and performance points of view. That’s 185why it is enforced in the language and the example above always produces 186compile-time errors. In exchange, we give our running engine much more 187information and guarantees about possible type values, which helps better 188optimize performance. 189