1/*
2 * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16let obj = {n: 42, s: 'foo'} // OK in TypeScript, CTE in ArkTS: unknown type of obj.
17
18class C {
19  n: number = 0;
20  s: string = "";
21}
22
23let c1: C = {n: 42, s: 'foo'} // Declaration + initialization: type of the literla is inferred from the type of c1.
24
25let c2: C;
26c2 = {n: 42, s: 'foo'}; // Initialization after declaration: type of the literal is inferred from the type of c2.
27
28let c3: Object = {n: 42, s: 'foo'} as C as Object; // Type of the literal is inferred from the 'as' cast.
29console.log(c3 instanceof C); // NB! Output is true in ArkTS, but is false in TS.
30
31function foo(c: C) {
32  console.log('foo is called');
33}
34
35foo({n: 42, s: 'foo'}); // Parsing as an argument: type of the literal is inferred from the type of parameter 'c'
36
37function bar(): C {
38  return {n: 42, s: 'foo'}; // Returning from function: type of the literal is inferred from the bar's return type.
39}
40
41let cc: C[] = [{n: 1, s: '1'}, {n: 2, s: '2'}]; // Type of the literal is inferred from the type of the array.
42
43class D {
44  b: boolean = false;
45  c: C = {n: 0, s: ""};
46}
47
48let d: D = {
49  b: true,
50  c: { // Initialization of a field with a literal: type of the literal is inferred from the definition of class D.
51    n: 42,
52    s: 'foo'
53  }
54}
55
56// Restrictions of classes that can be initialized with literal
57// Default initializable class.
58class C1 {
59  n: number = 0;
60  s?: string;
61}
62
63let c4: C1 = {n: 42}; // OK in TS, OK in ArkTS, c.s is null
64
65class C2 {
66  s: string;
67  constructor(s: string) {
68    this.s = "s = " + s;
69  }
70}
71
72let c5: C2 = {s: 'foo'} // OK in TS, CTE in ArkTS
73
74// All class fields are accessible at the point of initialization.
75class C3 {
76  private n: number = 0;
77  public s: string = '';
78}
79
80// CTE in TypeScript, CTE in ArkTS // let c6: C3 = {n: 42, s: 'foo'},
81
82class C4 {
83  readonly n: number = 0;
84  readonly s: string = '';
85}
86
87let c7: C4 = {n: 42, s: 'foo'}; // OK in TS, CTE in ArkTS
88
89// Class is non-abstract
90abstract class A {}
91let a: A = {}; // OK in TS, CTE in ArkTS
92
93// Class declares no methods, apart from optionally declared constructors and setters.
94class C5 {
95  n: number = 0;
96  s: string = '';
97  f() {
98    console.log('C5.f is called');
99  }
100}
101
102let c8: C5 = {n: 42, s: 'foo', f: () => {}} // OK in TS, CTE in ArkTS
103
104// NB! If a class has getters/setters the semantics of initialization differs:
105class C6 {
106  n: number = 0;
107  _s: string = '';
108  get s(): string { return this._s; }
109  set s(s: string) { this._s = s; }
110}
111
112let c9: C6 = {n: 42, _s: 'foo', s: 'bar'}
113console.log(c9.s); // TS: 'bar', ArkTS: 'bar'
114console.log(c9._s); // TS: 'foo', ArkTS: 'bar'
115
116// Extra fields are not allowed (eventually it means that it's not possible to assign literals to Object / object):
117class C7 {
118  n: number = 0;
119  s: string = '';
120}
121// TS: CTE, ArtTS: CTE // let c10: C7 = {n: 42, s: '', extra: true},
122let o1: Object = {s: '', n: 42} // OK in TS, CTE in ArkTS: no fields 'n' and 's' in Object
123let o2: object = {n: 42, s: ''} // OK in TS, CTE in ArkTS: no fields 'n' and 's' in object
124
125// If initialized class is inherited from another class, the base class must also be literal-initializable,
126// and initialization should happen from the 'glattened' literal:
127class Base {
128  n: number = 0;
129}
130
131class Derived extends Base {
132  s: string = '';
133}
134
135let d2: Derived = {n: 42, s: ''};
136
137// Interface should not declare methods, only properties are allowed. 
138interface I {
139  n: number;
140  s: string;
141  f(): void;
142}
143
144let i: I = {n: 42, s: '', f: () => {console.log('I.f is called')}} // OK in TypeScript, CTE in ArkTS
145
146// Interface properties of reference types must be default-initializable:
147interface I2 {
148  n: number;
149  s: string; // Assuming that 'string' is an alias for 'String', and there is String() constructor (what is true).
150}
151
152let i2: I2 = {n: 42, s: ''};
153
154interface CompilerOptions {
155  strict?: boolean;
156  sourcePath?: string;
157  targetPath?: string;
158}
159
160const options: CompilerOptions = { // OK, as 'targetPath' field is optional
161  strict: true,
162  sourcePath: './src',
163};
164
165// Function parameter with union type. 
166function funcWithUnionParam(x: C | number): void { }
167funcWithUnionParam({ n: 1, s: '2' }) // OK, union type is supported
168
169// issue 13022: property with union type
170class UnionProperty {
171    a: number | string = 123;
172    b?: boolean | number;
173}
174let u: UnionProperty = { a: 1 }; // OK, union type is supported
175u = { a: '2' }; // OK, union type is supported
176u = { a: 3, b: true }; // OK, union type is supported
177
178// issue 13022: optional property
179class OptionalProp {
180  a?: number;
181}
182let o: OptionalProp = {};
183o = {a: 1}; // OK
184
185class OptionalProp2 {
186    a?: number;
187    b: string;
188}
189function optProp(a: OptionalProp2) {}
190optProp({b: ''}); // OK
191optProp({a: 0, b: '1'}); // OK
192
193// Property with inheritance
194class E1 {
195  x: number;
196  y: Base;
197}
198let e1 : E1 = {
199  x: 1,
200  y: new Derived()
201}
202
203// Property with inheritance through generic type parameter
204class E2<T> {
205  x: number;
206  y: T;
207}
208let e2 : E2<Base> = {
209  x: 1,
210  y: new Derived()
211}
212
213// Type alias chain to interface
214interface ITypeAlias<T> { a: number; b: T }
215type ITA<T> = ITypeAlias<T>;
216type ITA2<K> = ITA<K>;
217let ti: ITA2<string> = { // OK, 'ITA2' is an alias to interface 'ITypeAlias'
218    a: 12,
219    b: '34'
220}
221
222// Type alias chain to class
223class CTypeAlias<T> {
224    a: number;
225    b: T;
226}
227type CTA<T> = CTypeAlias<T>;
228type CTA2<K> = CTA<K>;
229let tc: CTA2<string> = { // OK, 'CTA' is an alias to class 'CTypeAlias'
230    a: 4,
231    b: '4'
232}
233
234// issue 13114: Const enum value converted to string/number type.
235const enum ATTRIBUTE {
236  ROW = 'Row',
237  COLUMN = 'Column',
238  COLUMN_REVERSE = 'ColumnReverse',
239};
240const enum GROUP {
241  MAIN_DIRECTION = 'MAIN_DIRECTION',
242};
243enum Orientation {
244  Horizontal,
245  Vertical
246}
247class ContainerModuleItem {
248  groupName: string = '';
249  attributeList: string[] = [];
250  attribute: ATTRIBUTE = ATTRIBUTE.COLUMN;
251  orientation: number = 0;
252}
253const FLEX_MODULE: ContainerModuleItem[] = [
254  {
255    groupName: GROUP.MAIN_DIRECTION,
256    attributeList: [ATTRIBUTE.COLUMN, ATTRIBUTE.ROW, ATTRIBUTE.COLUMN_REVERSE],
257    attribute: ATTRIBUTE.ROW,
258    orientation: Orientation.Horizontal
259  }
260];
261
262interface I3 {}
263
264class CCl implements I3 {}
265
266class CCl2 extends CCl implements I3 {}
267
268interface I4 {
269        a: I3;
270        b: I3;
271        c: CCl;
272        d: CCl2;
273}
274
275class DCl {
276        constructor(a: I4) {}
277}
278
279let c: I4 = {a: new CCl(), b: new CCl2(), c: new CCl2(), d: new CCl2()}
280
281new DCl({a: new CCl(), b: new CCl2(), c: new CCl2(), d: new CCl2()})
282
283let oo1: Object = {}
284
285let oo2: Object = {a: 12}
286