jotai-state-tree 0.1.0

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.
package/src/types.ts ADDED
@@ -0,0 +1,520 @@
1
+ /**
2
+ * Core types for jotai-state-tree
3
+ * These types mirror the MobX-State-Tree API
4
+ */
5
+
6
+ // ============================================================================
7
+ // Snapshot Types
8
+ // ============================================================================
9
+
10
+ export type SnapshotIn<T> =
11
+ T extends IModelType<infer P, any, any, any>
12
+ ? { [K in keyof P]?: SnapshotInOfProperty<P[K]> }
13
+ : T extends IArrayType<infer I>
14
+ ? SnapshotIn<I>[]
15
+ : T extends IMapType<infer V>
16
+ ? Record<string, SnapshotIn<V>>
17
+ : T extends IReferenceType<any>
18
+ ? string | number
19
+ : T extends IType<infer C, any, any>
20
+ ? C
21
+ : T;
22
+
23
+ type SnapshotInOfProperty<T> = T extends IType<infer C, any, any> ? C : never;
24
+
25
+ export type SnapshotOut<T> =
26
+ T extends IModelType<infer P, any, any, any>
27
+ ? { [K in keyof P]: SnapshotOutOfProperty<P[K]> }
28
+ : T extends IArrayType<infer I>
29
+ ? SnapshotOut<I>[]
30
+ : T extends IMapType<infer V>
31
+ ? Record<string, SnapshotOut<V>>
32
+ : T extends IReferenceType<any>
33
+ ? string | number
34
+ : T extends IType<any, infer S, any>
35
+ ? S
36
+ : T;
37
+
38
+ type SnapshotOutOfProperty<T> = T extends IType<any, infer S, any> ? S : never;
39
+
40
+ export type Instance<T> = T extends IType<any, any, infer O> ? O : never;
41
+
42
+ // ============================================================================
43
+ // Base Type Interface
44
+ // ============================================================================
45
+
46
+ export interface IType<C, S, T> {
47
+ /** Name of this type */
48
+ readonly name: string;
49
+
50
+ /** The identifier attribute if this type has one */
51
+ readonly identifierAttribute?: string;
52
+
53
+ /** Create an instance of this type */
54
+ create(snapshot?: C, env?: unknown): T;
55
+
56
+ /** Check if a value is an instance of this type */
57
+ is(value: unknown): value is T;
58
+
59
+ /** Validate a value against this type */
60
+ validate(value: unknown, context: IValidationContext[]): IValidationResult;
61
+
62
+ /** Type discriminator */
63
+ readonly _kind: string;
64
+
65
+ // Phantom types for TypeScript inference
66
+ readonly _C: C;
67
+ readonly _S: S;
68
+ readonly _T: T;
69
+ }
70
+
71
+ export interface IValidationContext {
72
+ path: string;
73
+ type: IType<unknown, unknown, unknown>;
74
+ parent: unknown;
75
+ }
76
+
77
+ export interface IValidationResult {
78
+ valid: boolean;
79
+ errors: IValidationError[];
80
+ }
81
+
82
+ export interface IValidationError {
83
+ context: IValidationContext[];
84
+ value: unknown;
85
+ message: string;
86
+ }
87
+
88
+ // ============================================================================
89
+ // Simple/Primitive Types
90
+ // ============================================================================
91
+
92
+ export interface ISimpleType<T> extends IType<T, T, T> {
93
+ readonly _kind: "simple";
94
+ }
95
+
96
+ // ============================================================================
97
+ // Model Types
98
+ // ============================================================================
99
+
100
+ export type ModelProperties = Record<string, IType<unknown, unknown, unknown>>;
101
+
102
+ export type ModelCreationType<P extends ModelProperties> = {
103
+ [K in keyof P]?: P[K] extends IType<infer C, unknown, unknown> ? C : never;
104
+ };
105
+
106
+ export type ModelSnapshotType<P extends ModelProperties> = {
107
+ [K in keyof P]: P[K] extends IType<unknown, infer S, unknown> ? S : never;
108
+ };
109
+
110
+ export type ModelInstanceType<P extends ModelProperties> = {
111
+ [K in keyof P]: P[K] extends IType<unknown, unknown, infer T> ? T : never;
112
+ };
113
+
114
+ /** Represents a node in the state tree */
115
+ export interface IStateTreeNode<S = unknown> {
116
+ readonly $id: string;
117
+ readonly $type: IType<unknown, unknown, unknown>;
118
+ readonly $parent: IStateTreeNode | null;
119
+ readonly $path: string;
120
+ readonly $env: unknown;
121
+ readonly $isAlive: boolean;
122
+ }
123
+
124
+ export type ModelInstance<
125
+ P extends ModelProperties,
126
+ V extends object,
127
+ A extends object,
128
+ Vol extends object,
129
+ > = ModelInstanceType<P> & {
130
+ /** Access to the tree node metadata */
131
+ readonly $treenode: IStateTreeNode;
132
+ };
133
+
134
+ export type ModelViews<Self, V> = (self: Self) => V;
135
+ export type ModelActions<Self, A> = (self: Self) => A;
136
+ export type ModelVolatile<Self, Vol> = (self: Self) => Vol;
137
+
138
+ export interface IModelType<
139
+ P extends ModelProperties,
140
+ V extends object,
141
+ A extends object,
142
+ Vol extends object,
143
+ > extends IType<
144
+ ModelCreationType<P>,
145
+ ModelSnapshotType<P>,
146
+ ModelInstance<P, V, A, Vol> & V & A & Vol
147
+ > {
148
+ readonly _kind: "model";
149
+ readonly properties: P;
150
+
151
+ /** Create a new model type with a different name */
152
+ named(name: string): IModelType<P, V, A, Vol>;
153
+
154
+ /** Add properties to the model */
155
+ props<P2 extends ModelProperties>(
156
+ properties: P2,
157
+ ): IModelType<P & P2, V, A, Vol>;
158
+
159
+ /** Add computed views to the model */
160
+ views<V2 extends object>(
161
+ fn: ModelViews<ModelInstance<P, V, A, Vol> & V & A & Vol, V2>,
162
+ ): IModelType<P, V & V2, A, Vol>;
163
+
164
+ /** Add actions to the model */
165
+ actions<A2 extends object>(
166
+ fn: ModelActions<ModelInstance<P, V, A, Vol> & V & A & Vol, A2>,
167
+ ): IModelType<P, V, A & A2, Vol>;
168
+
169
+ /** Add volatile (non-serialized) state */
170
+ volatile<Vol2 extends object>(
171
+ fn: ModelVolatile<ModelInstance<P, V, A, Vol> & V & A & Vol, Vol2>,
172
+ ): IModelType<P, V, A, Vol & Vol2>;
173
+
174
+ /** Transform snapshot before creating instance */
175
+ preProcessSnapshot<NewC>(
176
+ fn: (snapshot: NewC) => ModelCreationType<P>,
177
+ ): IModelType<P, V, A, Vol>;
178
+
179
+ /** Transform snapshot after getting it */
180
+ postProcessSnapshot<NewS>(
181
+ fn: (snapshot: ModelSnapshotType<P>) => NewS,
182
+ ): IModelType<P, V, A, Vol>;
183
+
184
+ /** Extend the model with views, actions, and state in one call */
185
+ extend<
186
+ V2 extends object = object,
187
+ A2 extends object = object,
188
+ Vol2 extends object = object,
189
+ >(
190
+ fn: (self: ModelInstance<P, V, A, Vol> & V & A & Vol) => {
191
+ views?: V2;
192
+ actions?: A2;
193
+ state?: Vol2;
194
+ },
195
+ ): IModelType<P, V & V2, A & A2, Vol & Vol2>;
196
+
197
+ /** Add afterCreate lifecycle hook */
198
+ afterCreate(
199
+ fn: (self: ModelInstance<P, V, A, Vol> & V & A & Vol) => void,
200
+ ): IModelType<P, V, A, Vol>;
201
+
202
+ /** Add afterAttach lifecycle hook (called when node is attached to tree) */
203
+ afterAttach(
204
+ fn: (self: ModelInstance<P, V, A, Vol> & V & A & Vol) => void,
205
+ ): IModelType<P, V, A, Vol>;
206
+
207
+ /** Add beforeDetach lifecycle hook (called before node is detached from tree) */
208
+ beforeDetach(
209
+ fn: (self: ModelInstance<P, V, A, Vol> & V & A & Vol) => void,
210
+ ): IModelType<P, V, A, Vol>;
211
+
212
+ /** Add beforeDestroy lifecycle hook (called before node is destroyed) */
213
+ beforeDestroy(
214
+ fn: (self: ModelInstance<P, V, A, Vol> & V & A & Vol) => void,
215
+ ): IModelType<P, V, A, Vol>;
216
+ }
217
+
218
+ // ============================================================================
219
+ // Array Type
220
+ // ============================================================================
221
+
222
+ /**
223
+ * MST Array interface that allows both instance types and snapshot/creation types
224
+ * for mutation methods like push(), unshift(), splice(), etc.
225
+ *
226
+ * @template T - The instance type of array items
227
+ * @template C - The creation/snapshot type of array items (defaults to T)
228
+ */
229
+ export interface IMSTArray<T, C = T>
230
+ extends Omit<Array<T>, "push" | "unshift" | "splice" | "fill"> {
231
+ /** Array length */
232
+ readonly length: number;
233
+ /** Push items (accepts both instances and snapshots) */
234
+ push(...items: (T | C)[]): number;
235
+ /** Unshift items (accepts both instances and snapshots) */
236
+ unshift(...items: (T | C)[]): number;
237
+ /** Splice items (accepts both instances and snapshots for new items) */
238
+ splice(start: number, deleteCount?: number, ...items: (T | C)[]): T[];
239
+ /** Fill with value */
240
+ fill(value: T | C, start?: number, end?: number): this;
241
+ /** Replace all items */
242
+ replace(items: (T | C)[]): void;
243
+ /** Remove all items */
244
+ clear(): void;
245
+ /** Remove a specific item */
246
+ remove(item: T): boolean;
247
+ /** Splice with array argument */
248
+ spliceWithArray(
249
+ index: number,
250
+ deleteCount?: number,
251
+ newItems?: (T | C)[],
252
+ ): T[];
253
+ /** Convert to JSON */
254
+ toJSON(): T[];
255
+ /** Index access */
256
+ [index: number]: T;
257
+ /** Iterator */
258
+ [Symbol.iterator](): IterableIterator<T>;
259
+ }
260
+
261
+ export interface IArrayType<T extends IType<unknown, unknown, unknown>>
262
+ extends IType<
263
+ Array<T extends IType<infer C, unknown, unknown> ? C : never>,
264
+ Array<T extends IType<unknown, infer S, unknown> ? S : never>,
265
+ IMSTArray<
266
+ T extends IType<unknown, unknown, infer I> ? I : never,
267
+ T extends IType<infer C, unknown, unknown> ? C : never
268
+ >
269
+ > {
270
+ readonly _kind: "array";
271
+ readonly _subType: T;
272
+ }
273
+
274
+ // ============================================================================
275
+ // Map Type
276
+ // ============================================================================
277
+
278
+ export interface IMSTMap<V> extends Map<string, V> {
279
+ /** Put a value, returning it */
280
+ put(value: V): V;
281
+ /** Merge values into the map */
282
+ merge(values: Record<string, V> | Map<string, V>): this;
283
+ /** Replace all values */
284
+ replace(values: Record<string, V> | Map<string, V>): this;
285
+ /** Convert to JSON */
286
+ toJSON(): Record<string, V>;
287
+ }
288
+
289
+ export interface IMapType<T extends IType<unknown, unknown, unknown>>
290
+ extends IType<
291
+ Record<string, T extends IType<infer C, unknown, unknown> ? C : never>,
292
+ Record<string, T extends IType<unknown, infer S, unknown> ? S : never>,
293
+ IMSTMap<T extends IType<unknown, unknown, infer I> ? I : never>
294
+ > {
295
+ readonly _kind: "map";
296
+ readonly _subType: T;
297
+ }
298
+
299
+ // ============================================================================
300
+ // Optional Type
301
+ // ============================================================================
302
+
303
+ export interface IOptionalType<
304
+ T extends IType<unknown, unknown, unknown>,
305
+ Default,
306
+ > extends IType<
307
+ (T extends IType<infer C, unknown, unknown> ? C : never) | undefined,
308
+ T extends IType<unknown, infer S, unknown> ? S : never,
309
+ T extends IType<unknown, unknown, infer I> ? I : never
310
+ > {
311
+ readonly _kind: "optional";
312
+ readonly _subType: T;
313
+ readonly _defaultValue: Default | (() => Default);
314
+ }
315
+
316
+ // ============================================================================
317
+ // Maybe Types
318
+ // ============================================================================
319
+
320
+ export interface IMaybeType<T extends IType<unknown, unknown, unknown>>
321
+ extends IType<
322
+ (T extends IType<infer C, unknown, unknown> ? C : never) | undefined,
323
+ (T extends IType<unknown, infer S, unknown> ? S : never) | undefined,
324
+ (T extends IType<unknown, unknown, infer I> ? I : never) | undefined
325
+ > {
326
+ readonly _kind: "maybe";
327
+ readonly _subType: T;
328
+ }
329
+
330
+ export interface IMaybeNullType<T extends IType<unknown, unknown, unknown>>
331
+ extends IType<
332
+ (T extends IType<infer C, unknown, unknown> ? C : never) | null,
333
+ (T extends IType<unknown, infer S, unknown> ? S : never) | null,
334
+ (T extends IType<unknown, unknown, infer I> ? I : never) | null
335
+ > {
336
+ readonly _kind: "maybeNull";
337
+ readonly _subType: T;
338
+ }
339
+
340
+ // ============================================================================
341
+ // Reference Type
342
+ // ============================================================================
343
+
344
+ export interface IReferenceType<T extends IAnyModelType>
345
+ extends IType<string | number, string | number, Instance<T>> {
346
+ readonly _kind: "reference";
347
+ readonly _targetType: T;
348
+ }
349
+
350
+ export interface ReferenceOptions<T extends IAnyModelType> {
351
+ get?(identifier: string | number, parent: unknown): Instance<T> | undefined;
352
+ set?(value: Instance<T>, parent: unknown): string | number;
353
+ onInvalidated?: (event: {
354
+ parent: unknown;
355
+ invalidId: string | number;
356
+ replaceRef: (newRef: Instance<T> | null) => void;
357
+ removeRef: () => void;
358
+ cause: "destroy" | "invalidSnapshotReference" | "detach";
359
+ }) => void;
360
+ }
361
+
362
+ export interface ISafeReferenceType<T extends IAnyModelType>
363
+ extends IType<
364
+ string | number | undefined,
365
+ string | number | undefined,
366
+ Instance<T> | undefined
367
+ > {
368
+ readonly _kind: "safeReference";
369
+ readonly _targetType: T;
370
+ }
371
+
372
+ // ============================================================================
373
+ // Union Type
374
+ // ============================================================================
375
+
376
+ export type UnionOptions = {
377
+ dispatcher?: (snapshot: unknown) => IType<unknown, unknown, unknown>;
378
+ eager?: boolean;
379
+ };
380
+
381
+ export interface IUnionType<Types extends IType<unknown, unknown, unknown>[]>
382
+ extends IType<
383
+ Types[number] extends IType<infer C, unknown, unknown> ? C : never,
384
+ Types[number] extends IType<unknown, infer S, unknown> ? S : never,
385
+ Types[number] extends IType<unknown, unknown, infer T> ? T : never
386
+ > {
387
+ readonly _kind: "union";
388
+ readonly _types: Types;
389
+ }
390
+
391
+ // ============================================================================
392
+ // Literal Type
393
+ // ============================================================================
394
+
395
+ export interface ILiteralType<T extends string | number | boolean>
396
+ extends IType<T, T, T> {
397
+ readonly _kind: "literal";
398
+ readonly _value: T;
399
+ }
400
+
401
+ // ============================================================================
402
+ // Enumeration Type
403
+ // ============================================================================
404
+
405
+ export interface IEnumerationType<E extends string> extends IType<E, E, E> {
406
+ readonly _kind: "enumeration";
407
+ readonly _options: readonly E[];
408
+ }
409
+
410
+ // ============================================================================
411
+ // Frozen Type
412
+ // ============================================================================
413
+
414
+ export interface IFrozenType<T> extends IType<T, T, T> {
415
+ readonly _kind: "frozen";
416
+ }
417
+
418
+ // ============================================================================
419
+ // Late Type
420
+ // ============================================================================
421
+
422
+ export interface ILateType<T extends IType<unknown, unknown, unknown>>
423
+ extends IType<
424
+ T extends IType<infer C, unknown, unknown> ? C : never,
425
+ T extends IType<unknown, infer S, unknown> ? S : never,
426
+ T extends IType<unknown, unknown, infer I> ? I : never
427
+ > {
428
+ readonly _kind: "late";
429
+ readonly _definition: () => T;
430
+ }
431
+
432
+ // ============================================================================
433
+ // Refinement Type
434
+ // ============================================================================
435
+
436
+ export interface IRefinementType<T extends IType<unknown, unknown, unknown>>
437
+ extends IType<
438
+ T extends IType<infer C, unknown, unknown> ? C : never,
439
+ T extends IType<unknown, infer S, unknown> ? S : never,
440
+ T extends IType<unknown, unknown, infer I> ? I : never
441
+ > {
442
+ readonly _kind: "refinement";
443
+ readonly _subType: T;
444
+ readonly _predicate: (value: unknown) => boolean;
445
+ }
446
+
447
+ // ============================================================================
448
+ // Custom Type
449
+ // ============================================================================
450
+
451
+ export interface CustomTypeOptions<C, S, T> {
452
+ name: string;
453
+ fromSnapshot(snapshot: S): T;
454
+ toSnapshot(value: T): S;
455
+ isTargetType(value: unknown): boolean;
456
+ getValidationMessage(value: unknown): string;
457
+ }
458
+
459
+ // ============================================================================
460
+ // Identifier Types
461
+ // ============================================================================
462
+
463
+ export interface IIdentifierType extends IType<string, string, string> {
464
+ readonly _kind: "identifier";
465
+ readonly identifierAttribute: string;
466
+ }
467
+
468
+ export interface IIdentifierNumberType extends IType<number, number, number> {
469
+ readonly _kind: "identifierNumber";
470
+ readonly identifierAttribute: string;
471
+ }
472
+
473
+ // ============================================================================
474
+ // Patch Types
475
+ // ============================================================================
476
+
477
+ export interface IJsonPatch {
478
+ op: "replace" | "add" | "remove";
479
+ path: string;
480
+ value?: unknown;
481
+ }
482
+
483
+ export interface IReversibleJsonPatch extends IJsonPatch {
484
+ oldValue?: unknown;
485
+ }
486
+
487
+ // ============================================================================
488
+ // Helper Types
489
+ // ============================================================================
490
+
491
+ export type IAnyType = IType<unknown, unknown, unknown>;
492
+
493
+ export type IAnyModelType = IModelType<ModelProperties, object, object, object>;
494
+
495
+ export type IAnyComplexType =
496
+ | IAnyModelType
497
+ | IArrayType<IAnyType>
498
+ | IMapType<IAnyType>;
499
+
500
+ /** Extract the creation type from a type */
501
+ export type CreationType<T extends IAnyType> =
502
+ T extends IType<infer C, unknown, unknown> ? C : never;
503
+
504
+ /** Extract the snapshot type from a type */
505
+ export type SnapshotType<T extends IAnyType> =
506
+ T extends IType<unknown, infer S, unknown> ? S : never;
507
+
508
+ /** Extract the instance type from a type */
509
+ export type InstanceType<T extends IAnyType> =
510
+ T extends IType<unknown, unknown, infer I> ? I : never;
511
+
512
+ // ============================================================================
513
+ // Tree Navigation Types
514
+ // ============================================================================
515
+
516
+ export type LivelinessMode = "warn" | "error" | "ignore";
517
+
518
+ export interface IDisposer {
519
+ (): void;
520
+ }