Skip to content

Commit

Permalink
fix(core): return a readonly signal on asReadonly. (#54719)
Browse files Browse the repository at this point in the history
Previous `asReadonly()` returned the signal value and not the signal itself.

Fixes #54704

PR Close #54719
  • Loading branch information
JeanMeche authored and pkozlowski-opensource committed Mar 6, 2024
1 parent c75c168 commit 443e5f1
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 4 deletions.
4 changes: 2 additions & 2 deletions packages/core/src/authoring/model/model_signal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {producerAccessed, SIGNAL, signalSetFn} from '@angular/core/primitives/si

import {RuntimeError, RuntimeErrorCode} from '../../errors';
import {Signal} from '../../render3/reactivity/api';
import {WritableSignal} from '../../render3/reactivity/signal';
import {signalAsReadonlyFn, WritableSignal} from '../../render3/reactivity/signal';
import {ɵINPUT_SIGNAL_BRAND_READ_TYPE, ɵINPUT_SIGNAL_BRAND_WRITE_TYPE} from '../input/input_signal';
import {INPUT_SIGNAL_NODE, InputSignalNode, REQUIRED_UNSET_VALUE} from '../input/input_signal_node';

Expand Down Expand Up @@ -71,7 +71,7 @@ export function createModelSignal<T>(initialValue: T): ModelSignal<T> {
}

(getter as any)[SIGNAL] = node;
(getter as any).asReadonly = (() => getter()) as Signal<T>;
(getter as any).asReadonly = signalAsReadonlyFn.bind(getter as any) as () => Signal<T>;

getter.set = (newValue: T) => {
if (!node.equal(node.value, newValue)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/render3/reactivity/signal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export function signal<T>(initialValue: T, options?: CreateSignalOptions<T>): Wr
return signalFn as WritableSignal<T>;
}

function signalAsReadonlyFn<T>(this: SignalGetter<T>): Signal<T> {
export function signalAsReadonlyFn<T>(this: SignalGetter<T>): Signal<T> {
const node = this[SIGNAL] as SignalNode<T>& {readonlyFn?: Signal<T>};
if (node.readonlyFn === undefined) {
const readonlyFn = () => this();
Expand Down
13 changes: 12 additions & 1 deletion packages/core/test/authoring/model_input_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/

import {computed} from '@angular/core';
import {computed, isSignal, WritableSignal} from '@angular/core';
import {model} from '@angular/core/src/authoring/model/model';
import {ModelSignal} from '@angular/core/src/authoring/model/model_signal';
import {TestBed} from '@angular/core/testing';

/**
* Utility type representing a signal that can be subscribed to. This is already captured
Expand Down Expand Up @@ -44,6 +45,16 @@ describe('model signal', () => {
expect(signal()).toBe(18);
});

it('should return readonly signal', () => {
const signal = model(2);
const readOnly = signal.asReadonly();

expect(isSignal(readOnly)).toBeTrue();
expect(readOnly()).toBe(2);
expect((readOnly as WritableSignal<unknown>).set).toBeUndefined();
expect((readOnly as WritableSignal<unknown>).update).toBeUndefined();
});

it('should emit when the value changes', () => {
const signal = model(1) as SubscribableSignal<number>;
const values: number[] = [];
Expand Down

0 comments on commit 443e5f1

Please sign in to comment.