Skip to content

Commit ef149de

Browse files
alxhubatscott
authored andcommitted
refactor(core): expose ReactiveNode privately on signal functions (#49529)
Signal functions are marked with a `[SIGNAL]` symbol property, which was previously set to `true`. This commit changes the `[SIGNAL]` property to have the `ReactiveNode` as its value instead. This doesn't change the behavior of the signal library itself, but exposes the signal internals in a way where developer tooling can look at any signal and interact with its dependency graph. PR Close #49529
1 parent 9e40250 commit ef149de

File tree

4 files changed

+12
-9
lines changed

4 files changed

+12
-9
lines changed

goldens/public-api/core/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1361,7 +1361,7 @@ export function setTestabilityGetter(getter: GetTestability): void;
13611361

13621362
// @public
13631363
export type Signal<T> = (() => DeepReadonly<T>) & {
1364-
[SIGNAL]: true;
1364+
[SIGNAL]: unknown;
13651365
};
13661366

13671367
// @public

packages/core/src/signals/src/api.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9+
import {ReactiveNode} from './graph';
10+
911
/**
1012
* Symbol used to tell `Signal`s apart from other functions.
1113
*
@@ -24,22 +26,22 @@ const SIGNAL = Symbol('SIGNAL');
2426
* @developerPreview
2527
*/
2628
export type Signal<T> = (() => DeepReadonly<T>)&{
27-
[SIGNAL]: true;
29+
[SIGNAL]: unknown;
2830
};
2931

3032
/**
3133
* Checks if the given `value` function is a reactive `Signal`.
3234
*/
3335
export function isSignal(value: Function): value is Signal<unknown> {
34-
return (value as Signal<unknown>)[SIGNAL] ?? false;
36+
return (value as Signal<unknown>)[SIGNAL] !== undefined;
3537
}
3638

3739
/**
3840
* Converts `fn` into a marked signal function (where `isSignal(fn)` will be `true`).
3941
*
4042
* @param fn A zero-argument function which will be converted into a `Signal`.
4143
*/
42-
export function createSignalFromFunction<T>(fn: () => T): Signal<T>;
44+
export function createSignalFromFunction<T>(node: ReactiveNode, fn: () => T): Signal<T>;
4345

4446
/**
4547
* Converts `fn` into a marked signal function (where `isSignal(fn)` will be `true`), and
@@ -50,15 +52,15 @@ export function createSignalFromFunction<T>(fn: () => T): Signal<T>;
5052
* desired interface for the `Signal`.
5153
*/
5254
export function createSignalFromFunction<T, U extends Record<string, unknown>>(
53-
fn: () => T, extraApi: U): Signal<T>&U;
55+
node: ReactiveNode, fn: () => T, extraApi: U): Signal<T>&U;
5456

5557
/**
5658
* Converts `fn` into a marked signal function (where `isSignal(fn)` will be `true`), and
5759
* potentially add some set of extra properties (passed as an object record `extraApi`).
5860
*/
5961
export function createSignalFromFunction<T, U extends Record<string, unknown> = {}>(
60-
fn: () => T, extraApi: U = ({} as U)): Signal<T>&U {
61-
(fn as any)[SIGNAL] = true;
62+
node: ReactiveNode, fn: () => T, extraApi: U = ({} as U)): Signal<T>&U {
63+
(fn as any)[SIGNAL] = node;
6264
// Copy properties from `extraApi` to `fn` to complete the desired API of the `Signal`.
6365
return Object.assign(fn, extraApi) as (Signal<T>& U);
6466
}

packages/core/src/signals/src/computed.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export function computed<T>(computation: () => T, options?: CreateComputedOption
3232

3333
// Casting here is required for g3, as TS inference behavior is slightly different between our
3434
// version/options and g3's.
35-
return createSignalFromFunction(node.signal.bind(node)) as unknown as Signal<T>;
35+
return createSignalFromFunction(node, node.signal.bind(node)) as unknown as Signal<T>;
3636
}
3737

3838
/**

packages/core/src/signals/src/signal.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,10 @@ export interface CreateSignalOptions<T> {
106106
*/
107107
export function signal<T>(initialValue: T, options?: CreateSignalOptions<T>): WritableSignal<T> {
108108
const signalNode = new WritableSignalImpl(initialValue, options?.equal ?? defaultEquals);
109+
109110
// Casting here is required for g3, as TS inference behavior is slightly different between our
110111
// version/options and g3's.
111-
const signalFn = createSignalFromFunction(signalNode.signal.bind(signalNode), {
112+
const signalFn = createSignalFromFunction(signalNode, signalNode.signal.bind(signalNode), {
112113
set: signalNode.set.bind(signalNode),
113114
update: signalNode.update.bind(signalNode),
114115
mutate: signalNode.mutate.bind(signalNode),

0 commit comments

Comments
 (0)