Skip to content

Commit

Permalink
fix assignment of subtypes (#7) (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gvozd authored Jan 17, 2025
1 parent c3adec8 commit b8ee846
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 9 deletions.
6 changes: 2 additions & 4 deletions src/computed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {defaultEquals, ValueEqualityFn} from './equality.js';
import {defaultEquals, ValueEqualityComparer} from './equality.js';
import {
consumerAfterComputation,
consumerBeforeComputation,
Expand All @@ -22,7 +22,7 @@ import {
*
* `Computed`s are both producers and consumers of reactivity.
*/
export interface ComputedNode<T> extends ReactiveNode {
export interface ComputedNode<T> extends ReactiveNode, ValueEqualityComparer<T> {
/**
* Current value of the computation, or one of the sentinel values above (`UNSET`, `COMPUTING`,
* `ERROR`).
Expand All @@ -39,8 +39,6 @@ export interface ComputedNode<T> extends ReactiveNode {
* The computation function which will produce a new value.
*/
computation: () => T;

equal: ValueEqualityFn<T>;
}

export type ComputedGetter<T> = (() => T) & {
Expand Down
8 changes: 6 additions & 2 deletions src/equality.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@
*/

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

/**
* The default equality function used for `signal` and `computed`, which uses referential equality.
Expand Down
16 changes: 16 additions & 0 deletions src/public-api-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,19 @@ expectTypeOf<keyof Signal.subtle.Watcher & string>().toEqualTypeOf<
expectTypeOf(new Signal.State(0)).toEqualTypeOf<Signal.State<number>>();
expectTypeOf(new Signal.State(0).get()).toEqualTypeOf<number>();
expectTypeOf(new Signal.State(0).set(1)).toEqualTypeOf<void>();

/**
* Assigning subtypes works
*/
expectTypeOf<Signal.Computed<Narrower>>().toMatchTypeOf<Signal.Computed<Broader>>();
expectTypeOf<Signal.State<Narrower>>().toMatchTypeOf<Signal.State<Broader>>();

/**
* Test data types
*/
interface Broader {
strProp: string;
}
interface Narrower extends Broader {
numProp: number;
}
5 changes: 2 additions & 3 deletions src/signal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

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

export interface SignalNode<T> extends ReactiveNode {
export interface SignalNode<T> extends ReactiveNode, ValueEqualityComparer<T> {
value: T;
equal: ValueEqualityFn<T>;
}

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

0 comments on commit b8ee846

Please sign in to comment.