Skip to content

Commit 443e5f1

Browse files
JeanMechepkozlowski-opensource
authored andcommitted
fix(core): return a readonly signal on asReadonly. (#54719)
Previous `asReadonly()` returned the signal value and not the signal itself. Fixes #54704 PR Close #54719
1 parent c75c168 commit 443e5f1

File tree

3 files changed

+15
-4
lines changed

3 files changed

+15
-4
lines changed

packages/core/src/authoring/model/model_signal.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {producerAccessed, SIGNAL, signalSetFn} from '@angular/core/primitives/si
1010

1111
import {RuntimeError, RuntimeErrorCode} from '../../errors';
1212
import {Signal} from '../../render3/reactivity/api';
13-
import {WritableSignal} from '../../render3/reactivity/signal';
13+
import {signalAsReadonlyFn, WritableSignal} from '../../render3/reactivity/signal';
1414
import {ɵINPUT_SIGNAL_BRAND_READ_TYPE, ɵINPUT_SIGNAL_BRAND_WRITE_TYPE} from '../input/input_signal';
1515
import {INPUT_SIGNAL_NODE, InputSignalNode, REQUIRED_UNSET_VALUE} from '../input/input_signal_node';
1616

@@ -71,7 +71,7 @@ export function createModelSignal<T>(initialValue: T): ModelSignal<T> {
7171
}
7272

7373
(getter as any)[SIGNAL] = node;
74-
(getter as any).asReadonly = (() => getter()) as Signal<T>;
74+
(getter as any).asReadonly = signalAsReadonlyFn.bind(getter as any) as () => Signal<T>;
7575

7676
getter.set = (newValue: T) => {
7777
if (!node.equal(node.value, newValue)) {

packages/core/src/render3/reactivity/signal.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export function signal<T>(initialValue: T, options?: CreateSignalOptions<T>): Wr
8181
return signalFn as WritableSignal<T>;
8282
}
8383

84-
function signalAsReadonlyFn<T>(this: SignalGetter<T>): Signal<T> {
84+
export function signalAsReadonlyFn<T>(this: SignalGetter<T>): Signal<T> {
8585
const node = this[SIGNAL] as SignalNode<T>& {readonlyFn?: Signal<T>};
8686
if (node.readonlyFn === undefined) {
8787
const readonlyFn = () => this();

packages/core/test/authoring/model_input_spec.ts

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

9-
import {computed} from '@angular/core';
9+
import {computed, isSignal, WritableSignal} from '@angular/core';
1010
import {model} from '@angular/core/src/authoring/model/model';
1111
import {ModelSignal} from '@angular/core/src/authoring/model/model_signal';
12+
import {TestBed} from '@angular/core/testing';
1213

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

48+
it('should return readonly signal', () => {
49+
const signal = model(2);
50+
const readOnly = signal.asReadonly();
51+
52+
expect(isSignal(readOnly)).toBeTrue();
53+
expect(readOnly()).toBe(2);
54+
expect((readOnly as WritableSignal<unknown>).set).toBeUndefined();
55+
expect((readOnly as WritableSignal<unknown>).update).toBeUndefined();
56+
});
57+
4758
it('should emit when the value changes', () => {
4859
const signal = model(1) as SubscribableSignal<number>;
4960
const values: number[] = [];

0 commit comments

Comments
 (0)