1e41f4b71Sopenharmony_ci# ArkCompiler Subsystem Changelog
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## cl.ArkCompiler.1 TypeScript Syntax Check Change
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ci**Access Level** 
6e41f4b71Sopenharmony_ciOther
7e41f4b71Sopenharmony_ci
8e41f4b71Sopenharmony_ci**Reason for Change** 
9e41f4b71Sopenharmony_ciThe TypeScript version in the OpenHarmony SDK is upgraded from 4.2.3 to 4.9.5. The new version supports more syntax features and provides higher type check capabilities. However, there are a few syntax features that are incompatible with earlier versions.
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ci**Change Occurrence Version** 
12e41f4b71Sopenharmony_ciOpenHarmony SDK 4.1.3.1
13e41f4b71Sopenharmony_ci
14e41f4b71Sopenharmony_ci**Change Impact** 
15e41f4b71Sopenharmony_ciCompared with earlier versions, the syntax check in the new TypeScript version is stricter. It has 10 types of syntax features that are incompatible with the existing syntax. The following describes these syntax features and provides simple examples.
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ci**Changed Syntax Features and Adaptation Guide**
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ci1. Union enums cannot be compared to arbitrary numbers. 
20e41f4b71Sopenharmony_ciEnums are considered union enums when their members are either automatically filled in, or trivially written. An enum of this type can recall each value that it potentially represents.
21e41f4b71Sopenharmony_ciThe following is an incorrect example:
22e41f4b71Sopenharmony_ci
23e41f4b71Sopenharmony_ci    ```
24e41f4b71Sopenharmony_ci    enum E {
25e41f4b71Sopenharmony_ci      A = 0,
26e41f4b71Sopenharmony_ci      B = 1,
27e41f4b71Sopenharmony_ci    }
28e41f4b71Sopenharmony_ci    function doSomething(x: E) {
29e41f4b71Sopenharmony_ci      // Error! This condition will always return 'false' since the types 'E' and '-1' have no overlap.
30e41f4b71Sopenharmony_ci      if (x === -1) {
31e41f4b71Sopenharmony_ci        // ...
32e41f4b71Sopenharmony_ci      }
33e41f4b71Sopenharmony_ci    }
34e41f4b71Sopenharmony_ci    ```
35e41f4b71Sopenharmony_ci    Adaptation suggestion: Use the **toString()** method to convert a number into a string for comparison.
36e41f4b71Sopenharmony_ci
37e41f4b71Sopenharmony_ci2. More compliant indirect calls to imported functions. 
38e41f4b71Sopenharmony_ci   When an import from a non-ES module (such as the commonjs module in the FA model) is called, the **this** value is discarded, just as when an import from an ES module is called. 
39e41f4b71Sopenharmony_ci   The following example shows the change:
40e41f4b71Sopenharmony_ci   ```
41e41f4b71Sopenharmony_ci    // Assume that this is the imported module, which has a 'foo' and 'feature' export.
42e41f4b71Sopenharmony_ci    let fooModule = {
43e41f4b71Sopenharmony_ci      foo() {
44e41f4b71Sopenharmony_ci        console.log(this);
45e41f4b71Sopenharmony_ci      },
46e41f4b71Sopenharmony_ci      feature: 'oh'
47e41f4b71Sopenharmony_ci    };
48e41f4b71Sopenharmony_ci
49e41f4b71Sopenharmony_ci    // Behavior before the change:
50e41f4b71Sopenharmony_ci    fooModule.foo(); // Output: {"feature": "oh"}
51e41f4b71Sopenharmony_ci    
52e41f4b71Sopenharmony_ci    // Behavior after the change (in effect, '(0, fooModule.foo) is called, which is slightly different from the preceding behavior):
53e41f4b71Sopenharmony_ci    (0, fooModule.foo)(); // Output: undefined
54e41f4b71Sopenharmony_ci   ```
55e41f4b71Sopenharmony_ci3. Abstract properties do not allow initializers. 
56e41f4b71Sopenharmony_ciThe following code will report an error because abstract properties are not allowed have initializers:
57e41f4b71Sopenharmony_ci    ```
58e41f4b71Sopenharmony_ci    abstract class C {
59e41f4b71Sopenharmony_ci      abstract prop = 1;
60e41f4b71Sopenharmony_ci      //       ~~~~
61e41f4b71Sopenharmony_ci      // Property 'prop' cannot have an initializer because it is marked abstract.
62e41f4b71Sopenharmony_ci    }
63e41f4b71Sopenharmony_ci    ```
64e41f4b71Sopenharmony_ci    Adaptation suggestion: Delete the initializer.
65e41f4b71Sopenharmony_ci4. The rest parameter syntax deletes unexpandable members from generic objects. 
66e41f4b71Sopenharmony_ciWhen being deconstructed from generic objects, properties are regarded as all deconstructible in earlier versions. In the new version, they are strictly analyzed to find out whether they can be deconstructed. Properties that should not be deconstructed include private properties, private methods, and static properties. The following code will report an error:
67e41f4b71Sopenharmony_ci    ```
68e41f4b71Sopenharmony_ci    class Thing {
69e41f4b71Sopenharmony_ci      someProperty = 42;
70e41f4b71Sopenharmony_ci      someMethod() {
71e41f4b71Sopenharmony_ci        // ...
72e41f4b71Sopenharmony_ci      }
73e41f4b71Sopenharmony_ci    }
74e41f4b71Sopenharmony_ci    function foo<T extends Thing>(x: T) {
75e41f4b71Sopenharmony_ci      let { someProperty, ...rest } = x;
76e41f4b71Sopenharmony_ci      // Used to work, is now an error!
77e41f4b71Sopenharmony_ci      // Property 'someMethod' does not exist on type 'Omit<T, "someProperty" | "someMethod">'.
78e41f4b71Sopenharmony_ci      rest.someMethod();
79e41f4b71Sopenharmony_ci    }
80e41f4b71Sopenharmony_ci    ```
81e41f4b71Sopenharmony_ci    Adaptation suggestion: When deconstructing a property from a generic object, make sure it can be deconstructed.
82e41f4b71Sopenharmony_ci5. There are stricter checks with template string expressions. 
83e41f4b71Sopenharmony_ciIf a symbol value is used in JavaScript, both JavaScript and TypeScript will throw an error. However, TypeScript now checks whether a generic value contained in a symbol is used in the template string. 
84e41f4b71Sopenharmony_ci    ```
85e41f4b71Sopenharmony_ci    function logKey<S extends string | symbol>(key: S): S {
86e41f4b71Sopenharmony_ci        // Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'.
87e41f4b71Sopenharmony_ci        console.log(`${key} is the key`);
88e41f4b71Sopenharmony_ci        return key;
89e41f4b71Sopenharmony_ci    }
90e41f4b71Sopenharmony_ci    ```
91e41f4b71Sopenharmony_ci    Adaptation suggestion: Wrap the expression in **'String(...)'**.
92e41f4b71Sopenharmony_ci6. Read-only tuples have a read-only length property. 
93e41f4b71Sopenharmony_ci    The read-only tuple now treats the length property as read-only. This can be seen for tuples with optional trailing and rest element types.
94e41f4b71Sopenharmony_ci    ```
95e41f4b71Sopenharmony_ci    function overwriteLength(tuple: readonly [string, string, string]) {
96e41f4b71Sopenharmony_ci        // Now errors.
97e41f4b71Sopenharmony_ci        tuple.length = 7;
98e41f4b71Sopenharmony_ci    }
99e41f4b71Sopenharmony_ci    ```
100e41f4b71Sopenharmony_ci7. Objects cannot be compared with array literals. 
101e41f4b71Sopenharmony_ciValue-comparison operations '==' and '===' between objects (and arrays) in JavaScript check whether two references point to the same value. Now the following code will report an error:
102e41f4b71Sopenharmony_ci    ```
103e41f4b71Sopenharmony_ci    if (peopleAtHome === []) {
104e41f4b71Sopenharmony_ci    //  ~~~~~~~~~~~~~~~~~~~
105e41f4b71Sopenharmony_ci    // This condition will always return 'false' since JavaScript compares objects by reference, not value.
106e41f4b71Sopenharmony_ci        console.log("here's where I lie, broken inside. </3")
107e41f4b71Sopenharmony_ci        adoptAnimals();
108e41f4b71Sopenharmony_ci    }
109e41f4b71Sopenharmony_ci    ```
110e41f4b71Sopenharmony_ci8. Unused renames are not allowed in type signatures. 
111e41f4b71Sopenharmony_ciIn the following example, you might think that **makePerson** takes an object with a **name** property of the string type and an **age** property of the number type. However, the destructuring syntax is actually taking precedence here. **makePerson** renames **name** and **age** to **string** and **number** respectively.
112e41f4b71Sopenharmony_ci    ```
113e41f4b71Sopenharmony_ci    declare function makePerson({ name: string, age: number }): Person;
114e41f4b71Sopenharmony_ci    ```
115e41f4b71Sopenharmony_ci    The correct way to write the above signature is as follows: 
116e41f4b71Sopenharmony_ci    ```
117e41f4b71Sopenharmony_ci    declare function makePerson(options: { name: string, age: number }): Person;
118e41f4b71Sopenharmony_ci    // or
119e41f4b71Sopenharmony_ci    declare function makePerson({ name, age }: { name: string, age: number }): Person;
120e41f4b71Sopenharmony_ci    ```
121e41f4b71Sopenharmony_ci9. Checks for equality on NaN. 
122e41f4b71Sopenharmony_ciAn error will be reported on direct comparisons against NaN.
123e41f4b71Sopenharmony_ci    ```
124e41f4b71Sopenharmony_ci    function validate(someValue: number) {
125e41f4b71Sopenharmony_ci        return someValue !== NaN;
126e41f4b71Sopenharmony_ci        //     ~~~~~~~~~~~~~~~~~
127e41f4b71Sopenharmony_ci        // error: This condition will always return 'true'. Did you mean '!Number.isNaN(someValue)'?
128e41f4b71Sopenharmony_ci    }
129e41f4b71Sopenharmony_ci    ```
130e41f4b71Sopenharmony_ci    Adaptation suggestion: Use **Number.isNaN** instead.
131e41f4b71Sopenharmony_ci10. Errors caused by enhanced type inference and check capabilities 
132e41f4b71Sopenharmony_ciAfter TypeScript is upgraded to 4.9.5, its type inference and check capabilities are enhanced, and syntax errors other than those described above may be detected. Correcting these syntax errors help improve run-time performance.
133