@adaas/a-utils 0.1.18 → 0.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/index.d.mts +964 -354
  2. package/dist/index.d.ts +964 -354
  3. package/dist/index.js +1426 -714
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +1426 -714
  6. package/dist/index.mjs.map +1 -1
  7. package/examples/A-Channel-examples.ts +13 -11
  8. package/examples/A-Command-examples-2.ts +429 -0
  9. package/examples/A-Command-examples.ts +487 -202
  10. package/examples/A-StateMachine-examples.ts +609 -0
  11. package/package.json +3 -2
  12. package/src/index.ts +1 -2
  13. package/src/lib/A-Channel/A-Channel.component.ts +14 -74
  14. package/src/lib/A-Channel/A-Channel.error.ts +5 -5
  15. package/src/lib/A-Channel/A-Channel.types.ts +2 -10
  16. package/src/lib/A-Channel/A-ChannelRequest.context.ts +25 -74
  17. package/src/lib/A-Command/A-Command.constants.ts +78 -23
  18. package/src/lib/A-Command/A-Command.entity.ts +447 -119
  19. package/src/lib/A-Command/A-Command.error.ts +11 -0
  20. package/src/lib/A-Command/A-Command.types.ts +96 -20
  21. package/src/lib/A-Command/A-CommandExecution.context.ts +0 -0
  22. package/src/lib/A-Command/README.md +164 -68
  23. package/src/lib/A-Config/A-Config.container.ts +2 -2
  24. package/src/lib/A-Config/A-Config.context.ts +19 -5
  25. package/src/lib/A-Config/components/ConfigReader.component.ts +1 -1
  26. package/src/lib/A-Logger/A-Logger.component.ts +211 -35
  27. package/src/lib/A-Logger/A-Logger.constants.ts +50 -10
  28. package/src/lib/A-Logger/A-Logger.env.ts +17 -1
  29. package/src/lib/A-Memory/A-Memory.component.ts +440 -0
  30. package/src/lib/A-Memory/A-Memory.constants.ts +49 -0
  31. package/src/lib/A-Memory/A-Memory.context.ts +14 -118
  32. package/src/lib/A-Memory/A-Memory.error.ts +21 -0
  33. package/src/lib/A-Memory/A-Memory.types.ts +21 -0
  34. package/src/lib/A-Operation/A-Operation.context.ts +58 -0
  35. package/src/lib/A-Operation/A-Operation.types.ts +47 -0
  36. package/src/lib/A-StateMachine/A-StateMachine.component.ts +258 -0
  37. package/src/lib/A-StateMachine/A-StateMachine.constants.ts +18 -0
  38. package/src/lib/A-StateMachine/A-StateMachine.error.ts +10 -0
  39. package/src/lib/A-StateMachine/A-StateMachine.types.ts +20 -0
  40. package/src/lib/A-StateMachine/A-StateMachineTransition.context.ts +41 -0
  41. package/src/lib/A-StateMachine/README.md +391 -0
  42. package/tests/A-Channel.test.ts +17 -14
  43. package/tests/A-Command.test.ts +548 -460
  44. package/tests/A-Logger.test.ts +8 -4
  45. package/tests/A-Memory.test.ts +151 -115
  46. package/tests/A-Schedule.test.ts +2 -2
  47. package/tests/A-StateMachine.test.ts +760 -0
@@ -0,0 +1,440 @@
1
+ import { A_Component, A_Inject, A_Scope, A_Feature, A_Dependency, A_Context } from "@adaas/a-concept";
2
+ import { A_MemoryFeatures } from "./A-Memory.constants";
3
+ import { A_MemoryContext } from "./A-Memory.context";
4
+ import { A_MemoryError } from "./A-Memory.error";
5
+ import { A_OperationContext } from "../A-Operation/A-Operation.context";
6
+ import { A_MemoryOperationContext } from "./A-Memory.types";
7
+
8
+
9
+ export class A_Memory<
10
+ _StorageType extends Record<string, any> = Record<string, any>,
11
+ _SerializedType extends Record<string, any> = Record<string, any>
12
+ > extends A_Component {
13
+
14
+ protected _ready?: Promise<void>
15
+
16
+
17
+ get ready(): Promise<void> {
18
+ if (!this._ready) {
19
+ this._ready = this.init();
20
+ }
21
+ return this._ready;
22
+ }
23
+
24
+ // ======================================================================
25
+ // ======================A-Memory Lifecycle Hooks========================
26
+ // ======================================================================
27
+
28
+ @A_Feature.Extend()
29
+ /**
30
+ * Handles errors during memory operations
31
+ */
32
+ async [A_MemoryFeatures.onError](...args: any[]): Promise<void> {
33
+ // Handle error
34
+ }
35
+
36
+ @A_Feature.Extend()
37
+ /**
38
+ * Handles memory expiration
39
+ */
40
+ async [A_MemoryFeatures.onExpire](...args: any[]): Promise<void> {
41
+ // Clear memory on expire
42
+ }
43
+
44
+ @A_Feature.Extend()
45
+ /**
46
+ * Initializes the memory context
47
+ */
48
+ async [A_MemoryFeatures.onInit](
49
+ @A_Inject(A_MemoryContext) context: A_MemoryContext<_StorageType>,
50
+ ...args: any[]
51
+ ): Promise<void> {
52
+ // Initialize memory
53
+ if (!context) {
54
+ context = new A_MemoryContext<_StorageType>();
55
+ A_Context.scope(this).register(context);
56
+ }
57
+ }
58
+
59
+ @A_Feature.Extend()
60
+ async [A_MemoryFeatures.onDestroy](
61
+ @A_Inject(A_MemoryContext) context: A_MemoryContext<_StorageType>,
62
+ ...args: any[]): Promise<void> {
63
+ // Cleanup memory
64
+ context.clear();
65
+ }
66
+
67
+ @A_Feature.Extend()
68
+ /**
69
+ * Handles the 'get' operation for retrieving a value from memory
70
+ */
71
+ async [A_MemoryFeatures.onGet](
72
+ @A_Dependency.Required()
73
+ @A_Inject(A_OperationContext) operation: A_MemoryOperationContext,
74
+ @A_Inject(A_MemoryContext) context: A_MemoryContext<_StorageType>,
75
+ ...args: any[]
76
+ ): Promise<void> {
77
+ // Handle get operation
78
+ operation.succeed(context.get(operation.params.key));
79
+ }
80
+
81
+ @A_Feature.Extend()
82
+ /**
83
+ * Handles the 'has' operation for checking existence of a key in memory
84
+ */
85
+ async [A_MemoryFeatures.onHas](
86
+ @A_Dependency.Required()
87
+ @A_Inject(A_OperationContext) operation: A_MemoryOperationContext<boolean>,
88
+ @A_Inject(A_MemoryContext) context: A_MemoryContext<_StorageType>,
89
+ ...args: any[]
90
+ ): Promise<void> {
91
+ // Handle has operation
92
+ operation.succeed(context.has(operation.params.key));
93
+ }
94
+
95
+ @A_Feature.Extend()
96
+ /**
97
+ * Handles the 'set' operation for saving a value in memory
98
+ */
99
+ async [A_MemoryFeatures.onSet](
100
+ @A_Dependency.Required()
101
+ @A_Inject(A_OperationContext) operation: A_MemoryOperationContext,
102
+ @A_Inject(A_MemoryContext) context: A_MemoryContext<_StorageType>,
103
+ ...args: any[]
104
+ ): Promise<void> {
105
+ // Handle set operation
106
+ context.set(operation.params.key, operation.params.value);
107
+ }
108
+
109
+ @A_Feature.Extend()
110
+ /**
111
+ * Handles the 'drop' operation for removing a value from memory
112
+ */
113
+ async [A_MemoryFeatures.onDrop](
114
+ @A_Dependency.Required()
115
+ @A_Inject(A_OperationContext) operation: A_MemoryOperationContext,
116
+ @A_Inject(A_MemoryContext) context: A_MemoryContext<_StorageType>,
117
+ ...args: any[]
118
+ ): Promise<void> {
119
+ // Handle drop operation
120
+ context.drop(operation.params.key);
121
+ }
122
+
123
+ @A_Feature.Extend()
124
+ /**
125
+ * Handles the 'clear' operation for clearing all values from memory
126
+ */
127
+ async [A_MemoryFeatures.onClear](
128
+ @A_Dependency.Required()
129
+ @A_Inject(A_OperationContext) operation: A_MemoryOperationContext,
130
+ @A_Inject(A_MemoryContext) context: A_MemoryContext<_StorageType>,
131
+ ...args: any[]
132
+ ): Promise<void> {
133
+ // Handle clear operation
134
+ context.clear();
135
+ }
136
+
137
+
138
+
139
+ // ======================================================================
140
+ // =========================A-Memory Methods=============================
141
+ // ======================================================================
142
+
143
+ /**
144
+ * Initializes the memory context
145
+ */
146
+ async init() {
147
+ if (this._ready)
148
+ return this._ready;
149
+
150
+ const scope = new A_Scope({ name: 'A-Memory-Init-Scope' })
151
+ .inherit(A_Context.scope(this));
152
+
153
+ try {
154
+ await this.call(A_MemoryFeatures.onInit, scope);
155
+
156
+ } catch (error) {
157
+ const initError = new A_MemoryError({
158
+ title: A_MemoryError.MemoryInitializationError,
159
+ description: 'An error occurred during memory initialization',
160
+ originalError: error
161
+ })
162
+
163
+ scope.register(initError);
164
+
165
+ await this.call(A_MemoryFeatures.onError, scope);
166
+
167
+ scope.destroy();
168
+
169
+ throw initError;
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Destroys the memory context
175
+ *
176
+ * This method is responsible for cleaning up any resources
177
+ * used by the memory context and resetting its state.
178
+ */
179
+ async destroy() {
180
+
181
+ const scope = new A_Scope({ name: 'A-Memory-Destroy-Scope' })
182
+ .inherit(A_Context.scope(this));
183
+
184
+ try {
185
+ this._ready = undefined;
186
+
187
+ await this.call(A_MemoryFeatures.onDestroy, scope);
188
+
189
+ } catch (error) {
190
+ const destroyError = new A_MemoryError({
191
+ title: A_MemoryError.MemoryDestructionError,
192
+ description: 'An error occurred during memory destruction',
193
+ originalError: error
194
+ })
195
+
196
+ scope.register(destroyError);
197
+
198
+
199
+ await this.call(A_MemoryFeatures.onError, scope);
200
+
201
+ scope.destroy();
202
+
203
+ throw destroyError;
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Retrieves a value from the context memory
209
+ *
210
+ * @param key - memory key to retrieve
211
+ * @returns - value associated with the key or undefined if not found
212
+ */
213
+ async get<K extends keyof _StorageType>(
214
+ /**
215
+ * Key to retrieve the value for
216
+ */
217
+ key: K
218
+ ): Promise<_StorageType[K] | undefined> {
219
+
220
+ const operation = new A_OperationContext('get', { key });
221
+
222
+ const scope = new A_Scope({
223
+ name: 'A-Memory-Get-Operation-Scope',
224
+ fragments: [operation]
225
+ });
226
+
227
+ try {
228
+
229
+ await this.call(A_MemoryFeatures.onGet, scope);
230
+
231
+ scope.destroy();
232
+
233
+ return operation.result;
234
+
235
+ } catch (error) {
236
+ const getError = new A_MemoryError({
237
+ title: A_MemoryError.MemoryGetError,
238
+ description: `An error occurred while getting the value for key "${String(key)}"`,
239
+ originalError: error
240
+ });
241
+
242
+ scope.register(getError);
243
+
244
+ await this.call(A_MemoryFeatures.onError, scope);
245
+
246
+ scope.destroy();
247
+
248
+ throw getError;
249
+ }
250
+ }
251
+
252
+ /**
253
+ * Checks if a value exists in the context memory
254
+ *
255
+ * @param key - memory key to check
256
+ * @returns - true if key exists, false otherwise
257
+ */
258
+ async has(key: keyof _StorageType): Promise<boolean> {
259
+ const operation = new A_OperationContext('has', { key });
260
+
261
+ const scope = new A_Scope({
262
+ name: 'A-Memory-Has-Operation-Scope',
263
+ fragments: [operation]
264
+ });
265
+
266
+ try {
267
+
268
+ await this.call(A_MemoryFeatures.onHas, scope);
269
+
270
+ scope.destroy();
271
+
272
+ return operation.result;
273
+
274
+ } catch (error) {
275
+ const getError = new A_MemoryError({
276
+ title: A_MemoryError.MemoryHasError,
277
+ description: `An error occurred while checking existence for key "${String(key)}"`,
278
+ originalError: error
279
+ });
280
+
281
+ scope.register(getError);
282
+
283
+ await this.call(A_MemoryFeatures.onError, scope);
284
+
285
+ scope.destroy();
286
+
287
+ throw getError;
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Saves a value in the context memory
293
+ *
294
+ * @param key
295
+ * @param value
296
+ */
297
+ async set<K extends keyof _StorageType>(
298
+ /**
299
+ * Key to save the value under
300
+ */
301
+ key: K,
302
+ /**
303
+ * Value to save
304
+ */
305
+ value: _StorageType[K]
306
+ ): Promise<void> {
307
+ const operation = new A_OperationContext('set', { key, value });
308
+
309
+ const scope = new A_Scope({
310
+ name: 'A-Memory-Set-Operation-Scope',
311
+ fragments: [operation]
312
+ });
313
+
314
+ try {
315
+
316
+ await this.call(A_MemoryFeatures.onSet, scope);
317
+
318
+ } catch (error) {
319
+ const setError = new A_MemoryError({
320
+ title: A_MemoryError.MemorySetError,
321
+ description: `An error occurred while setting the value for key "${String(key)}"`,
322
+ originalError: error
323
+ });
324
+
325
+ scope.register(setError);
326
+
327
+ await this.call(A_MemoryFeatures.onError, scope);
328
+
329
+ scope.destroy();
330
+
331
+ throw setError;
332
+ }
333
+ }
334
+
335
+
336
+ /**
337
+ * Removes a value from the context memory by key
338
+ *
339
+ * @param key
340
+ */
341
+ async drop(key: keyof _StorageType): Promise<void> {
342
+
343
+ const operation = new A_OperationContext('drop', { key });
344
+
345
+ const scope = new A_Scope({
346
+ name: 'A-Memory-Drop-Operation-Scope',
347
+ fragments: [operation]
348
+ });
349
+
350
+ try {
351
+
352
+ await this.call(A_MemoryFeatures.onDrop, scope);
353
+
354
+ } catch (error) {
355
+ const dropError = new A_MemoryError({
356
+ title: A_MemoryError.MemoryDropError,
357
+ description: `An error occurred while dropping the value for key "${String(key)}"`,
358
+ originalError: error
359
+ });
360
+
361
+ scope.register(dropError);
362
+
363
+ await this.call(A_MemoryFeatures.onError, scope);
364
+
365
+ scope.destroy();
366
+
367
+ throw dropError;
368
+ }
369
+ }
370
+
371
+ /**
372
+ * Clears all stored values in the context memory
373
+ */
374
+ async clear(): Promise<void> {
375
+ const operation = new A_OperationContext('clear');
376
+
377
+ const scope = new A_Scope({
378
+ name: 'A-Memory-Clear-Operation-Scope',
379
+ fragments: [operation]
380
+ });
381
+
382
+ try {
383
+
384
+ await this.call(A_MemoryFeatures.onClear, scope);
385
+
386
+ } catch (error) {
387
+ const clearError = new A_MemoryError({
388
+ title: A_MemoryError.MemoryClearError,
389
+ description: `An error occurred while clearing the memory`,
390
+ originalError: error
391
+ });
392
+
393
+ scope.register(clearError);
394
+
395
+ await this.call(A_MemoryFeatures.onError, scope);
396
+
397
+ scope.destroy();
398
+
399
+ throw clearError;
400
+ }
401
+ }
402
+
403
+
404
+ /**
405
+ * Serializes the memory context to a JSON object
406
+ *
407
+ * @returns - serialized memory object
408
+ */
409
+ async toJSON(): Promise<_SerializedType> {
410
+ const operation = new A_OperationContext('serialize');
411
+
412
+ const scope = new A_Scope({
413
+ name: 'A-Memory-Serialize-Operation-Scope',
414
+ fragments: [operation]
415
+ });
416
+
417
+ try {
418
+
419
+ await this.call(A_MemoryFeatures.onSerialize, scope);
420
+
421
+ return operation.result as _SerializedType;
422
+
423
+ } catch (error) {
424
+ const serializeError = new A_MemoryError({
425
+ title: A_MemoryError.MemorySerializeError,
426
+ description: `An error occurred while serializing the memory`,
427
+ originalError: error
428
+ });
429
+
430
+ scope.register(serializeError);
431
+
432
+ await this.call(A_MemoryFeatures.onError, scope);
433
+
434
+ scope.destroy();
435
+
436
+ throw serializeError;
437
+ }
438
+
439
+ }
440
+ }
@@ -0,0 +1,49 @@
1
+
2
+
3
+ export enum A_MemoryFeatures {
4
+ /**
5
+ * Allows to extend initialization logic and behavior
6
+ */
7
+ onInit = 'onInit',
8
+
9
+ /**
10
+ * Allows to extend destruction logic and behavior
11
+ */
12
+ onDestroy = 'onDestroy',
13
+
14
+ /**
15
+ * Allows to extend expiration logic and behavior
16
+ */
17
+ onExpire = 'onExpire',
18
+
19
+ /**
20
+ * Allows to extend error handling logic and behavior
21
+ */
22
+ onError = 'onError',
23
+
24
+ /**
25
+ * Allows to extend serialization logic and behavior
26
+ */
27
+ onSerialize = 'onSerialize',
28
+
29
+ /**
30
+ * Allows to extend set operation logic and behavior
31
+ */
32
+ onSet = 'onSet',
33
+ /**
34
+ * Allows to extend get operation logic and behavior
35
+ */
36
+ onGet = 'onGet',
37
+ /**
38
+ * Allows to extend drop operation logic and behavior
39
+ */
40
+ onDrop = 'onDrop',
41
+ /**
42
+ * Allows to extend clear operation logic and behavior
43
+ */
44
+ onClear = 'onClear',
45
+ /**
46
+ * Allows to extend has operation logic and behavior
47
+ */
48
+ onHas = 'onHas',
49
+ }
@@ -1,130 +1,26 @@
1
- import { A_Error, A_Fragment } from "@adaas/a-concept";
1
+ import { A_Error, A_Fragment, A_TYPES__Fragment_Serialized } from "@adaas/a-concept";
2
+ import { error } from "console";
2
3
 
3
4
 
4
- export class A_Memory<
5
- _MemoryType extends Record<string, any> = Record<string, any>,
6
- _SerializedType extends Record<string, any> = Record<string, any>
7
- > extends A_Fragment {
8
-
9
-
10
- /**
11
- * Internal storage of all intermediate values
12
- */
13
- protected _memory: Map<keyof _MemoryType, _MemoryType[keyof _MemoryType]>;
14
- /**
15
- * Errors encountered during the execution
16
- */
17
- protected _errors: Set<A_Error>;
18
5
 
19
6
 
7
+ export class A_MemoryContext<
8
+ _MemoryType extends Record<string, any> = Record<string, any>,
9
+ _SerializedType extends A_TYPES__Fragment_Serialized = A_TYPES__Fragment_Serialized
10
+ > extends A_Fragment<_MemoryType, _MemoryType & _SerializedType> {
20
11
 
21
- /**
22
- * Memory object that allows to store intermediate values and errors
23
- *
24
- * @param initialValues
25
- */
26
- constructor(initialValues?: _MemoryType) {
27
- super();
28
- this._memory = new Map(Object.entries(initialValues || {}));
29
- this._errors = new Set();
30
- }
31
-
32
-
33
- get Errors(): Set<A_Error> | undefined {
34
- return this._errors.size > 0 ? this._errors : undefined;
35
- }
36
-
37
-
38
- /**
39
- * Verifies that all required keys are present in the proxy values
40
- *
41
- * @param requiredKeys
42
- * @returns
43
- */
44
- async prerequisites(
45
- requiredKeys: Array<keyof _MemoryType>
46
- ): Promise<boolean> {
47
- return requiredKeys.every(key => this._memory.has(key));
48
- }
49
-
50
- /**
51
- * Adds an error to the context
52
- *
53
- * @param error
54
- */
55
- async error(error: A_Error): Promise<void> {
56
- this._errors.add(error);
57
- }
58
12
 
59
- /**
60
- * Retrieves a value from the context memory
61
- *
62
- * @param key
63
- * @returns
64
- */
65
- get<K extends keyof _MemoryType>(
66
- /**
67
- * Key to retrieve the value for
68
- */
69
- key: K
70
- ): _MemoryType[K] | undefined {
71
- return this._memory.get(key);
13
+ set<K extends keyof _MemoryType>(param: 'error', value: A_Error): void
14
+ set<K extends keyof _MemoryType>(param: K, value: _MemoryType[K]): void
15
+ set<K extends keyof _MemoryType>(param: K | 'error', value: _MemoryType[K]): void {
16
+ super.set(param , value);
72
17
  }
73
18
 
74
- /**
75
- * Saves a value in the context memory
76
- *
77
- * @param key
78
- * @param value
79
- */
80
- async set<K extends keyof _MemoryType>(
81
- /**
82
- * Key to save the value under
83
- */
84
- key: K,
85
- /**
86
- * Value to save
87
- */
88
- value: _MemoryType[K]
89
- ): Promise<void> {
90
- this._memory.set(key, value);
91
- }
92
-
93
-
94
- /**
95
- * Removes a value from the context memory by key
96
- *
97
- * @param key
98
- */
99
- async drop(key: keyof _MemoryType): Promise<void> {
100
- this._memory.delete(key);
101
- }
102
19
 
103
- /**
104
- * Clears all stored values in the context memory
105
- */
106
- async clear(): Promise<void> {
107
- this._memory.clear();
20
+ get<K extends keyof A_Error>(param: 'error'): A_Error | undefined
21
+ get<K extends keyof _MemoryType>(param: K): _MemoryType[K] | undefined
22
+ get<K extends keyof _MemoryType>(param: K | 'error'): _MemoryType[K] | undefined {
23
+ return super.get(param);
108
24
  }
109
25
 
110
-
111
- /**
112
- * Converts all stored values to a plain object
113
- *
114
- * [!] By default uses all saved in memory values
115
- *
116
- * @returns
117
- */
118
- toJSON(): _SerializedType {
119
- const obj: Record<string, any> = {};
120
-
121
- this._memory.forEach((value, key) => {
122
- obj[key as string] =
123
- typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function'
124
- ? value.toJSON()
125
- : value;
126
- });
127
-
128
- return obj as _SerializedType;
129
- }
130
26
  }
@@ -0,0 +1,21 @@
1
+ import { A_Error } from "@adaas/a-concept";
2
+
3
+
4
+ export class A_MemoryError extends A_Error {
5
+
6
+ static readonly MemoryInitializationError = 'Memory initialization error';
7
+
8
+ static readonly MemoryDestructionError = 'Memory destruction error';
9
+
10
+ static readonly MemoryGetError = 'Memory GET operation failed';
11
+
12
+ static readonly MemorySetError = 'Memory SET operation failed';
13
+
14
+ static readonly MemoryDropError = 'Memory DROP operation failed';
15
+
16
+ static readonly MemoryClearError = 'Memory CLEAR operation failed';
17
+
18
+ static readonly MemoryHasError = 'Memory HAS operation failed';
19
+
20
+ static readonly MemorySerializeError = 'Memory toJSON operation failed';
21
+ }
@@ -0,0 +1,21 @@
1
+ import { A_Error } from "@adaas/a-concept"
2
+ import { A_OperationContext } from "../A-Operation/A-Operation.context";
3
+
4
+
5
+ export type A_MemoryContextMeta<T extends Record<string, any> = Record<string, any>> = Omit<T, 'error'> & {
6
+ error?: A_Error,
7
+ }
8
+
9
+ export type A_Memory_Storage = Record<string, any> & {
10
+ error?: A_Error,
11
+ }
12
+
13
+ export type A_MemoryOperations = 'get' | 'set' | 'drop' | 'clear' | 'has' | 'serialize';
14
+
15
+
16
+
17
+ export type A_MemoryOperationContext<T extends any = any> = A_OperationContext<
18
+ A_MemoryOperations,
19
+ { key: string, value?: any },
20
+ T
21
+ >;