@@ -69,26 +69,32 @@ export function createEffect(fn: Function) {
69
69
currentEffect = null ;
70
70
}
71
71
72
- function computed < T extends NormalSignal > ( val : ( ) => T ) : PrimitiveSignal < T > ;
73
- function computed < T extends any [ ] > ( val : ( ) => T ) : ArraySignal < T > ;
74
- function computed < T extends Record < any , any > > ( val : ( ) => T ) : ObjectSignal < T > ;
75
72
function computed < T extends NormalSignal | any [ ] | Record < any , any > > (
76
73
fn : ( ) => T
77
74
) {
78
75
if ( typeof fn !== "function" )
79
76
throw new Error ( "computed takes a function as the argument" ) ;
80
77
81
78
currentEffect = ( ) => {
82
- const newVal = fn ( ) ;
83
- signal . update ( newVal ) ;
79
+ let newVal = fn ( ) ;
80
+ if ( newVal !== signal . value ) {
81
+ signal . update ( newVal ) ;
82
+ }
84
83
} ;
84
+
85
85
addEffect ( currentEffect ) ;
86
+
86
87
const val = fn ( ) ;
87
- // @ts -expect-error
88
+
89
+ // @ts -expect-error - Type assertion for signal
88
90
const signal = createSignal < T > ( val ) ;
89
- currentEffect = null ;
90
91
91
- return signal ;
92
+ currentEffect = null ;
93
+ return {
94
+ get value ( ) {
95
+ return signal . value ;
96
+ } ,
97
+ } ;
92
98
}
93
99
94
100
type PromiseOverload < T > =
@@ -126,7 +132,11 @@ export function createPromise<T>(fn: () => Promise<T>) {
126
132
} ) ;
127
133
} ) ;
128
134
129
- return triggerSignal ;
135
+ return {
136
+ get value ( ) {
137
+ return triggerSignal . value ;
138
+ } ,
139
+ } ;
130
140
}
131
141
132
142
export class Ref < T extends HTMLElement > {
@@ -141,30 +151,43 @@ export function createRef<T extends HTMLElement>() {
141
151
return ref ;
142
152
}
143
153
144
- const NonMutatingArrayMethods = [
145
- "concat" ,
146
- "every" ,
147
- "filter" ,
148
- "find" ,
149
- "findIndex" ,
150
- "flat" ,
151
- "flatMap" ,
152
- "forEach" ,
153
- "includes" ,
154
- "indexOf" ,
155
- "join" ,
156
- "map" ,
157
- "reduce" ,
158
- "reduceRight" ,
159
- "slice" ,
160
- "some" ,
161
- "toLocaleString" ,
162
- "toString" ,
154
+ // const NonMutatingArrayMethods = [
155
+ // "constructor",
156
+ // "concat",
157
+ // "every",
158
+ // "filter",
159
+ // "find",
160
+ // "findIndex",
161
+ // "flat",
162
+ // "flatMap",
163
+ // "forEach",
164
+ // "includes",
165
+ // "indexOf",
166
+ // "join",
167
+ // "map",
168
+ // "reduce",
169
+ // "reduceRight",
170
+ // "slice",
171
+ // "some",
172
+ // "toLocaleString",
173
+ // "toString",
174
+ // ];
175
+ const MutatingMethods = [
176
+ "push" ,
177
+ "pop" ,
178
+ "unshift" ,
179
+ "shift" ,
180
+ "splice" ,
181
+ "fill" ,
182
+ "copyWithin" ,
183
+ "sort" ,
184
+ "reverse" ,
163
185
] ;
164
186
165
187
type DeepReadonly < T > = {
166
188
readonly [ K in keyof T ] : T [ K ] extends object ? DeepReadonly < T [ K ] > : T [ K ] ;
167
189
} ;
190
+
168
191
/**
169
192
*
170
193
* Base class for signals.
@@ -286,17 +309,18 @@ export class ArraySignal<T extends any[]> extends BaseSignal<T> {
286
309
287
310
if ( typeof value === "function" ) {
288
311
if (
289
- ! NonMutatingArrayMethods . includes ( String ( prop ) ) &&
312
+ MutatingMethods . includes ( String ( prop ) ) &&
290
313
! this . updateCalled
291
314
) {
292
315
throw new Error (
293
316
"Cannot set a value on an array signal, use the update method for updating the array."
294
317
) ;
295
318
}
319
+
296
320
return ( ...args : any [ ] ) => {
297
321
const result = value . apply ( target , args ) ;
298
322
// Notify if the method is mutating.
299
- if ( ! NonMutatingArrayMethods . includes ( String ( prop ) ) ) {
323
+ if ( MutatingMethods . includes ( String ( prop ) ) ) {
300
324
this . notify ( ) ;
301
325
}
302
326
return result ;
@@ -330,17 +354,6 @@ export class ArraySignal<T extends any[]> extends BaseSignal<T> {
330
354
return this . _val ;
331
355
}
332
356
333
- // set value(val: T) {
334
- // if (!Array.isArray(val)) {
335
- // throw new Error(
336
- // "Invalid type for ArraySignal; value must be an array"
337
- // );
338
- // }
339
- // if (val === this._val) return;
340
- // this._val = this.createProxy(val);
341
- // this.notify();
342
- // }
343
-
344
357
public update ( val : T | ( ( prev : T ) => void ) ) {
345
358
this . updateCalled = true ;
346
359
if ( typeof val === "function" ) {
@@ -383,16 +396,17 @@ export class ObjectSignal<T extends Record<any, any>> extends BaseSignal<T> {
383
396
if ( typeof value === "function" ) {
384
397
if (
385
398
! this . updateCalled &&
386
- ! NonMutatingArrayMethods . includes ( String ( prop ) )
399
+ MutatingMethods . includes ( String ( prop ) )
387
400
) {
388
401
throw new Error (
389
402
"Cannot set a value on an object signal, use the update method for updating the object."
390
403
) ;
391
404
}
405
+
392
406
return ( ...args : any [ ] ) => {
393
407
const result = value . apply ( target , args ) ;
394
408
// Notify if the method is mutating.
395
- if ( ! NonMutatingArrayMethods . includes ( String ( prop ) ) ) {
409
+ if ( MutatingMethods . includes ( String ( prop ) ) ) {
396
410
this . notify ( ) ;
397
411
}
398
412
return result ;
@@ -467,17 +481,6 @@ export class ObjectSignal<T extends Record<any, any>> extends BaseSignal<T> {
467
481
return this . _val ;
468
482
}
469
483
470
- // set value(val: T) {
471
- // if (!isPlainObject(val)) {
472
- // throw new Error(
473
- // "Invalid type for ObjectSignal; value must be a plain object"
474
- // );
475
- // }
476
- // if (val === this._val) return;
477
- // this._val = this.createProxy(val);
478
- // this.notify();
479
- // }
480
-
481
484
public update ( val : T | ( ( prev : T ) => void ) ) {
482
485
this . updateCalled = true ;
483
486
if ( typeof val === "function" ) {
@@ -496,12 +499,27 @@ export class ObjectSignal<T extends Record<any, any>> extends BaseSignal<T> {
496
499
}
497
500
}
498
501
502
+ export interface PublicSignal < T > {
503
+ readonly value : DeepReadonly < T > ;
504
+ update ( val : T | ( ( prev : T ) => T ) ) : void ;
505
+ }
506
+
507
+ export interface PublicArraySignal < T extends any [ ] > extends PublicSignal < T > {
508
+ update ( val : T | ( ( prev : T ) => void ) ) : void ; // Mutation allowed
509
+ }
510
+
511
+ export interface PublicObjectSignal < T extends Record < any , any > >
512
+ extends PublicSignal < T > {
513
+ update ( val : T | ( ( prev : T ) => void ) ) : void ; // Mutation allowed
514
+ }
499
515
/**
500
516
* Overloaded factory function to create a signal.
501
517
*/
502
- function createSignal < T extends NormalSignal > ( val : T ) : PrimitiveSignal < T > ;
503
- function createSignal < T extends any [ ] > ( val : T ) : ArraySignal < T > ;
504
- function createSignal < T extends Record < any , any > > ( val : T ) : ObjectSignal < T > ;
518
+ function createSignal < T extends NormalSignal > ( val : T ) : PublicSignal < T > ;
519
+ function createSignal < T extends any [ ] > ( val : T ) : PublicArraySignal < T > ;
520
+ function createSignal < T extends Record < any , any > > (
521
+ val : T
522
+ ) : PublicObjectSignal < T > ;
505
523
506
524
function createSignal < T extends NormalSignal | any [ ] | Record < any , any > > (
507
525
val : T
@@ -514,11 +532,21 @@ function createSignal<T extends NormalSignal | any[] | Record<any, any>>(
514
532
if ( Array . isArray ( val ) ) {
515
533
const signal = new ArraySignal ( val ) ;
516
534
addSignal ( signal ) ;
517
- return signal ;
535
+ return {
536
+ get value ( ) {
537
+ return signal . value ;
538
+ } ,
539
+ update : signal . update . bind ( signal ) as typeof signal . update ,
540
+ } ;
518
541
} else if ( isPlainObject ( val ) ) {
519
542
const signal = new ObjectSignal ( val ) ;
520
543
addSignal ( signal ) ;
521
- return signal ;
544
+ return {
545
+ get value ( ) {
546
+ return signal . value ;
547
+ } ,
548
+ update : signal . update . bind ( signal ) as typeof signal . update ,
549
+ } ;
522
550
} else {
523
551
throw new Error (
524
552
"Invalid type for signal initialization: " + typeof val
@@ -527,7 +555,12 @@ function createSignal<T extends NormalSignal | any[] | Record<any, any>>(
527
555
} else if ( isPrimitive ( val ) ) {
528
556
const signal = new PrimitiveSignal ( val ) ;
529
557
addSignal ( signal ) ;
530
- return signal ;
558
+ return {
559
+ get value ( ) {
560
+ return signal . value ;
561
+ } ,
562
+ update : signal . update . bind ( signal ) as typeof signal . update ,
563
+ } ;
531
564
} else {
532
565
throw new Error (
533
566
"Invalid type for signal initialization: " + typeof val
0 commit comments