Skip to content

Commit b8ee846

Browse files
authored
fix assignment of subtypes (#7) (#42)
1 parent c3adec8 commit b8ee846

File tree

4 files changed

+26
-9
lines changed

4 files changed

+26
-9
lines changed

src/computed.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {defaultEquals, ValueEqualityFn} from './equality.js';
9+
import {defaultEquals, ValueEqualityComparer} from './equality.js';
1010
import {
1111
consumerAfterComputation,
1212
consumerBeforeComputation,
@@ -22,7 +22,7 @@ import {
2222
*
2323
* `Computed`s are both producers and consumers of reactivity.
2424
*/
25-
export interface ComputedNode<T> extends ReactiveNode {
25+
export interface ComputedNode<T> extends ReactiveNode, ValueEqualityComparer<T> {
2626
/**
2727
* Current value of the computation, or one of the sentinel values above (`UNSET`, `COMPUTING`,
2828
* `ERROR`).
@@ -39,8 +39,6 @@ export interface ComputedNode<T> extends ReactiveNode {
3939
* The computation function which will produce a new value.
4040
*/
4141
computation: () => T;
42-
43-
equal: ValueEqualityFn<T>;
4442
}
4543

4644
export type ComputedGetter<T> = (() => T) & {

src/equality.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@
77
*/
88

99
/**
10-
* A comparison function which can determine if two values are equal.
10+
* An interface representing a comparison strategy to determine if two values are equal.
11+
*
12+
* @template T The type of the values to be compared.
1113
*/
12-
export type ValueEqualityFn<T> = (a: T, b: T) => boolean;
14+
export interface ValueEqualityComparer<T> {
15+
equal(a: T, b: T): boolean;
16+
}
1317

1418
/**
1519
* The default equality function used for `signal` and `computed`, which uses referential equality.

src/public-api-types.ts

+16
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,19 @@ expectTypeOf<keyof Signal.subtle.Watcher & string>().toEqualTypeOf<
9393
expectTypeOf(new Signal.State(0)).toEqualTypeOf<Signal.State<number>>();
9494
expectTypeOf(new Signal.State(0).get()).toEqualTypeOf<number>();
9595
expectTypeOf(new Signal.State(0).set(1)).toEqualTypeOf<void>();
96+
97+
/**
98+
* Assigning subtypes works
99+
*/
100+
expectTypeOf<Signal.Computed<Narrower>>().toMatchTypeOf<Signal.Computed<Broader>>();
101+
expectTypeOf<Signal.State<Narrower>>().toMatchTypeOf<Signal.State<Broader>>();
102+
103+
/**
104+
* Test data types
105+
*/
106+
interface Broader {
107+
strProp: string;
108+
}
109+
interface Narrower extends Broader {
110+
numProp: number;
111+
}

src/signal.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {defaultEquals, ValueEqualityFn} from './equality.js';
9+
import {defaultEquals, ValueEqualityComparer} from './equality.js';
1010
import {throwInvalidWriteToSignalError} from './errors.js';
1111
import {
1212
producerAccessed,
@@ -30,9 +30,8 @@ declare const ngDevMode: boolean | undefined;
3030
*/
3131
let postSignalSetFn: (() => void) | null = null;
3232

33-
export interface SignalNode<T> extends ReactiveNode {
33+
export interface SignalNode<T> extends ReactiveNode, ValueEqualityComparer<T> {
3434
value: T;
35-
equal: ValueEqualityFn<T>;
3635
}
3736

3837
export type SignalBaseGetter<T> = (() => T) & {readonly [SIGNAL]: unknown};

0 commit comments

Comments
 (0)