1e41f4b71Sopenharmony_ci# ArkUI Subsystem Changelog
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## cl.arkui.1 Verification Against Undefined Keys for Decorators
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ci**Access Level**
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciPublic
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ci**Reason for Change**
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ciThe **key** value should be verified for all decorators to comply with TypeScript syntax rules.
12e41f4b71Sopenharmony_ci
13e41f4b71Sopenharmony_ciThe following decorators are involved:
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ci@LocalStorageLink, @LocalStorageProp, @StorageProp, @StorageLink, @Provide, @Consume, @Watch
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ci**Change Impact**
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ciIf the **key** value of any of the aforementioned decorators is not defined, a compilation error is reported.
20e41f4b71Sopenharmony_ci
21e41f4b71Sopenharmony_ciThis change is a non-compatible change.
22e41f4b71Sopenharmony_ci
23e41f4b71Sopenharmony_ci**Start API Level**
24e41f4b71Sopenharmony_ci
25e41f4b71Sopenharmony_ci@LocalStorageLink: API version 9
26e41f4b71Sopenharmony_ci
27e41f4b71Sopenharmony_ci@LocalStorageProp: API version 9
28e41f4b71Sopenharmony_ci
29e41f4b71Sopenharmony_ci@StorageProp: API version 7
30e41f4b71Sopenharmony_ci
31e41f4b71Sopenharmony_ci@StorageLink: API version 7
32e41f4b71Sopenharmony_ci
33e41f4b71Sopenharmony_ci@Provide: API version 7
34e41f4b71Sopenharmony_ci
35e41f4b71Sopenharmony_ci@Consume: API version 7
36e41f4b71Sopenharmony_ci
37e41f4b71Sopenharmony_ci@Watch: API version 7
38e41f4b71Sopenharmony_ci
39e41f4b71Sopenharmony_ci
40e41f4b71Sopenharmony_ci
41e41f4b71Sopenharmony_ci**Change Since**
42e41f4b71Sopenharmony_ci
43e41f4b71Sopenharmony_ciOpenHarmony SDK 5.0.0.13
44e41f4b71Sopenharmony_ci
45e41f4b71Sopenharmony_ciExample:
46e41f4b71Sopenharmony_ci
47e41f4b71Sopenharmony_ci```
48e41f4b71Sopenharmony_ci@Entry
49e41f4b71Sopenharmony_ci@Component
50e41f4b71Sopenharmony_cistruct ComA {
51e41f4b71Sopenharmony_ci  // ERROR: Cannot find name 'aaa'.
52e41f4b71Sopenharmony_ci  @StorageProp(aaa) storageProp: string = 'storageProp';
53e41f4b71Sopenharmony_ci  // ERROR: Cannot find name 'aaa'.
54e41f4b71Sopenharmony_ci  @StorageLink(aaa) storageLink: string = 'storageLink';
55e41f4b71Sopenharmony_ci  // ERROR: Cannot find name 'aaa'.
56e41f4b71Sopenharmony_ci  @LocalStorageLink(aaa) localStorageLink: string = 'localStorageLink';
57e41f4b71Sopenharmony_ci  // ERROR: Cannot find name 'aaa'.
58e41f4b71Sopenharmony_ci  @LocalStorageProp(aaa) localStorageProp: string = 'localStorageProp';
59e41f4b71Sopenharmony_ci  // ERROR: Cannot find name 'aaa'.
60e41f4b71Sopenharmony_ci  @Provide(aaa) provide: string = 'provide';
61e41f4b71Sopenharmony_ci  // ERROR: Cannot find name 'aaa'.
62e41f4b71Sopenharmony_ci  @Consume(aaa) consume: number;
63e41f4b71Sopenharmony_ci  // ERROR: Cannot find name 'aaa'.
64e41f4b71Sopenharmony_ci  @State @Watch(aaa) watch: number = 0;
65e41f4b71Sopenharmony_ci
66e41f4b71Sopenharmony_ci  build() {
67e41f4b71Sopenharmony_ci  }
68e41f4b71Sopenharmony_ci}
69e41f4b71Sopenharmony_ci
70e41f4b71Sopenharmony_ci```
71e41f4b71Sopenharmony_ci
72e41f4b71Sopenharmony_ci**Adaptation Guide**
73e41f4b71Sopenharmony_ci
74e41f4b71Sopenharmony_ci Make sure the **key** value for the following decorators is defined: @LocalStorageLink, @LocalStorageProp, @StorageProp, @StorageLink, @Provide, @Consume, and @Watch.
75e41f4b71Sopenharmony_ci
76e41f4b71Sopenharmony_ci```
77e41f4b71Sopenharmony_ci// test.ts
78e41f4b71Sopenharmony_ciexport let oneKey = 'string';
79e41f4b71Sopenharmony_ci```
80e41f4b71Sopenharmony_ci
81e41f4b71Sopenharmony_ci
82e41f4b71Sopenharmony_ci
83e41f4b71Sopenharmony_ci```
84e41f4b71Sopenharmony_ci
85e41f4b71Sopenharmony_ci// index.ets
86e41f4b71Sopenharmony_ciimport { oneKey } from './test';
87e41f4b71Sopenharmony_ci@Entry
88e41f4b71Sopenharmony_ci@Component
89e41f4b71Sopenharmony_cistruct ComA {
90e41f4b71Sopenharmony_ci  @StorageProp(oneKey) storageProp: string = 'storageProp';
91e41f4b71Sopenharmony_ci  @StorageLink(oneKey) storageLink: string = 'storageLink';
92e41f4b71Sopenharmony_ci  @LocalStorageLink(oneKey) localStorageLink: string = 'localStorageLink';
93e41f4b71Sopenharmony_ci  @LocalStorageProp(oneKey) localStorageProp: string = 'localStorageProp';
94e41f4b71Sopenharmony_ci  @Provide(oneKey) provide: string = 'provide';
95e41f4b71Sopenharmony_ci  @Consume(oneKey) consume: number;
96e41f4b71Sopenharmony_ci
97e41f4b71Sopenharmony_ci  build() {
98e41f4b71Sopenharmony_ci  }
99e41f4b71Sopenharmony_ci}
100e41f4b71Sopenharmony_ci```
101e41f4b71Sopenharmony_ci
102e41f4b71Sopenharmony_ci
103e41f4b71Sopenharmony_ci
104e41f4b71Sopenharmony_ci
105e41f4b71Sopenharmony_ci## cl.arkui.2 Addition of undefined and null Support for AppStorage, LocalStorage, and PersistentStorage
106e41f4b71Sopenharmony_ci
107e41f4b71Sopenharmony_ci**Access Level**
108e41f4b71Sopenharmony_ci
109e41f4b71Sopenharmony_ciPublic
110e41f4b71Sopenharmony_ci
111e41f4b71Sopenharmony_ci**Change Impact**
112e41f4b71Sopenharmony_ci
113e41f4b71Sopenharmony_ciThe AppStorage, LocalStorage, and PersistentStorage APIs now accept **null** and **undefined** as input parameters. The @StorageLink, @StorageProp, @LocalStorageLink, and @LocalStorageProp decorators now support **null** and **undefined** types.
114e41f4b71Sopenharmony_ci
115e41f4b71Sopenharmony_ciTake @StorageLink as an example. If an AppStorage API uses **null** or **undefined** as the initial or target value, then: In the semantics before change, calling the API reports a warning and does not take effect. In the semantics after change, **null** or **undefined** is saved as the initial or target value in AppStorage. This change causes the original application code to crash in the following scenario:
116e41f4b71Sopenharmony_ci
117e41f4b71Sopenharmony_ciBefore change:
118e41f4b71Sopenharmony_ci
119e41f4b71Sopenharmony_ci```ts
120e41f4b71Sopenharmony_ciclass PropA {
121e41f4b71Sopenharmony_ci  num: number = 100;
122e41f4b71Sopenharmony_ci}
123e41f4b71Sopenharmony_ci
124e41f4b71Sopenharmony_ciAppStorage.setOrCreate("PropA", null);
125e41f4b71Sopenharmony_ciAppStorage.has("PropA");// Because null and undefined are not supported, false is returned.
126e41f4b71Sopenharmony_ci
127e41f4b71Sopenharmony_ci@Entry
128e41f4b71Sopenharmony_ci@Component
129e41f4b71Sopenharmony_cistruct TestPage {
130e41f4b71Sopenharmony_ci  @StorageLink('PropA') propA: PropA = new PropA();
131e41f4b71Sopenharmony_ci
132e41f4b71Sopenharmony_ci  build() {
133e41f4b71Sopenharmony_ci    Column() {
134e41f4b71Sopenharmony_ci      Text(this.propA.num.toString()) // propA is locally initialized to 100.
135e41f4b71Sopenharmony_ci    }
136e41f4b71Sopenharmony_ci  }
137e41f4b71Sopenharmony_ci}
138e41f4b71Sopenharmony_ci```
139e41f4b71Sopenharmony_ci
140e41f4b71Sopenharmony_ciAfter change:
141e41f4b71Sopenharmony_ci
142e41f4b71Sopenharmony_ci```ts
143e41f4b71Sopenharmony_ciclass PropA {
144e41f4b71Sopenharmony_ci  num: number = 100;
145e41f4b71Sopenharmony_ci}
146e41f4b71Sopenharmony_ci
147e41f4b71Sopenharmony_ciAppStorage.setOrCreate("PropA", null);
148e41f4b71Sopenharmony_ciAppStorage.has("PropA");// Because null and undefined are supported, true is returned.
149e41f4b71Sopenharmony_ci
150e41f4b71Sopenharmony_ci@Entry
151e41f4b71Sopenharmony_ci@Component
152e41f4b71Sopenharmony_cistruct TestPage {
153e41f4b71Sopenharmony_ci  @StorageLink('PropA') propA: PropA = new PropA();
154e41f4b71Sopenharmony_ci
155e41f4b71Sopenharmony_ci  build() {
156e41f4b71Sopenharmony_ci    Column() {
157e41f4b71Sopenharmony_ci      Text(this.propA.num.toString()) // propA is initialized with the value null in AppStorage. As a result, JsCrash is triggered during invoking.
158e41f4b71Sopenharmony_ci    }
159e41f4b71Sopenharmony_ci  }
160e41f4b71Sopenharmony_ci}
161e41f4b71Sopenharmony_ci```
162e41f4b71Sopenharmony_ci
163e41f4b71Sopenharmony_ci**Key API/Component Changes**
164e41f4b71Sopenharmony_ci
165e41f4b71Sopenharmony_ciAppStorage: **set**, **setOrCreate**, **setAndLink**, **setAndProp**
166e41f4b71Sopenharmony_ci
167e41f4b71Sopenharmony_ciLocalStorage: **set**, **setOrCreate**, **setAndLink**, **setAndProp**
168e41f4b71Sopenharmony_ci
169e41f4b71Sopenharmony_ciPersistentStorage: **persistProp**
170e41f4b71Sopenharmony_ci
171e41f4b71Sopenharmony_ci
172e41f4b71Sopenharmony_ci**Start API Level**
173e41f4b71Sopenharmony_ci
174e41f4b71Sopenharmony_ciThis change takes effect since API version 12.
175e41f4b71Sopenharmony_ci
176e41f4b71Sopenharmony_ciAppStorage
177e41f4b71Sopenharmony_ci
178e41f4b71Sopenharmony_ci**set**: API version 10
179e41f4b71Sopenharmony_ci
180e41f4b71Sopenharmony_ci**setOrCreate**: API version 10
181e41f4b71Sopenharmony_ci
182e41f4b71Sopenharmony_ci**setAndLink**: API version 10
183e41f4b71Sopenharmony_ci
184e41f4b71Sopenharmony_ci**setAndProp**: API version 10
185e41f4b71Sopenharmony_ci
186e41f4b71Sopenharmony_ciLocalStorage
187e41f4b71Sopenharmony_ci
188e41f4b71Sopenharmony_ci**set**: API version 9
189e41f4b71Sopenharmony_ci
190e41f4b71Sopenharmony_ci**setOrCreate**: API version 9
191e41f4b71Sopenharmony_ci
192e41f4b71Sopenharmony_ci**setAndLink**: API version 9
193e41f4b71Sopenharmony_ci
194e41f4b71Sopenharmony_ci**setAndProp**: API version 9
195e41f4b71Sopenharmony_ci
196e41f4b71Sopenharmony_ciPersistentStorage
197e41f4b71Sopenharmony_ci
198e41f4b71Sopenharmony_ci**persistProp**: API version 10
199e41f4b71Sopenharmony_ci
200e41f4b71Sopenharmony_ci**Change Since**
201e41f4b71Sopenharmony_ci
202e41f4b71Sopenharmony_ciOpenHarmony SDK 5.0.0.13
203e41f4b71Sopenharmony_ci
204e41f4b71Sopenharmony_ci**Adaptation Guide**
205e41f4b71Sopenharmony_ci
206e41f4b71Sopenharmony_ci1. Do not use **null** or **undefined** to initialize variables. Use meaningful values instead.
207e41f4b71Sopenharmony_ci
208e41f4b71Sopenharmony_ci2. Changing a value to **null** or **undefined** will trigger UI re-render.
209e41f4b71Sopenharmony_ci
210e41f4b71Sopenharmony_ci3. Add a null check to the invoking position.
211e41f4b71Sopenharmony_ci
212e41f4b71Sopenharmony_ci```ts
213e41f4b71Sopenharmony_ciclass PropA {
214e41f4b71Sopenharmony_ci  num: number = 100;
215e41f4b71Sopenharmony_ci}
216e41f4b71Sopenharmony_ci
217e41f4b71Sopenharmony_ciAppStorage.setOrCreate("PropA", null);
218e41f4b71Sopenharmony_ciAppStorage.has("PropA"); // Because null and undefined are supported, true is returned.
219e41f4b71Sopenharmony_ci
220e41f4b71Sopenharmony_ci@Entry
221e41f4b71Sopenharmony_ci@Component
222e41f4b71Sopenharmony_cistruct TestPage {
223e41f4b71Sopenharmony_ci  @StorageLink('PropA') propA: PropA | null | undefined = new PropA();
224e41f4b71Sopenharmony_ci
225e41f4b71Sopenharmony_ci  build() {
226e41f4b71Sopenharmony_ci    Column() {
227e41f4b71Sopenharmony_ci      Text(this.propA?.num.toString())// Check whether the value is null to prevent crashes caused by null and undefined during invoking.
228e41f4b71Sopenharmony_ci        .fontSize(20)
229e41f4b71Sopenharmony_ci      Button("Set propA to null")
230e41f4b71Sopenharmony_ci        .margin(10)
231e41f4b71Sopenharmony_ci        .onClick(() => {
232e41f4b71Sopenharmony_ci          this.propA = null;
233e41f4b71Sopenharmony_ci        })
234e41f4b71Sopenharmony_ci      Button("Set propA to undefined")
235e41f4b71Sopenharmony_ci        .margin(10)
236e41f4b71Sopenharmony_ci        .onClick(() => {
237e41f4b71Sopenharmony_ci          this.propA = undefined;
238e41f4b71Sopenharmony_ci        })
239e41f4b71Sopenharmony_ci      Button("Assign new PropA")
240e41f4b71Sopenharmony_ci        .margin(10)
241e41f4b71Sopenharmony_ci        .onClick(() => {
242e41f4b71Sopenharmony_ci          this.propA = new PropA();
243e41f4b71Sopenharmony_ci        })
244e41f4b71Sopenharmony_ci    }
245e41f4b71Sopenharmony_ci  }
246e41f4b71Sopenharmony_ci}
247e41f4b71Sopenharmony_ci```
248