Skip to content

Commit

Permalink
fix(signals): make patchState work with TS 5.4 (#4294)
Browse files Browse the repository at this point in the history
  • Loading branch information
markostanimirovic authored Apr 11, 2024
1 parent 9c3f845 commit 6b440ee
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 1 deletion.
72 changes: 72 additions & 0 deletions modules/signals/spec/types/patch-state.types.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { expecter } from 'ts-snippet';
import { compilerOptions } from './helpers';

describe('patchState', () => {
const expectSnippet = expecter(
(code) => `
import {
PartialStateUpdater,
patchState,
signalState,
} from '@ngrx/signals';
const state = signalState({ count: 1, foo: 'bar' });
function increment(): PartialStateUpdater<{ count: number }> {
return ({ count }) => ({ count: count + 1 });
}
function addNumber(num: number): PartialStateUpdater<{
numbers: number[];
}> {
return ({ numbers }) => ({ numbers: [...numbers, num] });
}
${code}
`,
compilerOptions()
);

it('infers the state type from StateSignal', () => {
expectSnippet('patchState(state, increment())').toSucceed();
expectSnippet("patchState(state, { foo: 'baz' })").toSucceed();
expectSnippet("patchState(state, { foo: 'baz' }, increment())").toSucceed();
expectSnippet("patchState(state, increment(), { foo: 'baz' })").toSucceed();
});

it('fails with wrong partial state object', () => {
expectSnippet('patchState(state, { x: 1 })').toFail(
/'x' does not exist in type 'Partial<{ count: number; foo: string; }>/
);
expectSnippet("patchState(state, { foo: 'baz' }, { x: 1 })").toFail(
/'x' does not exist in type 'Partial<{ count: number; foo: string; }>/
);
expectSnippet('patchState(state, { x: 1 }, { count: 0 })').toFail(
/'x' does not exist in type 'Partial<{ count: number; foo: string; }>/
);
expectSnippet('patchState(state, increment(), { x: 1 })').toFail(
/'x' does not exist in type 'Partial<{ count: number; foo: string; }>/
);
expectSnippet('patchState(state, { x: 1 }, increment())').toFail(
/'x' does not exist in type 'Partial<{ count: number; foo: string; }>/
);
});

it('fails with wrong partial state updater', () => {
expectSnippet('patchState(state, addNumber(10))').toFail(
/Property 'numbers' is missing in type '{ count: number; foo: string; }'/
);
expectSnippet('patchState(state, { count: 10 }, addNumber(10))').toFail(
/Property 'numbers' is missing in type '{ count: number; foo: string; }'/
);
expectSnippet('patchState(state, addNumber(10), { count: 10 })').toFail(
/Property 'numbers' is missing in type '{ count: number; foo: string; }'/
);
expectSnippet('patchState(state, increment(), addNumber(10))').toFail(
/Property 'numbers' is missing in type '{ count: number; foo: string; }'/
);
expectSnippet('patchState(state, addNumber(10), increment())').toFail(
/Property 'numbers' is missing in type '{ count: number; foo: string; }'/
);
});
});
5 changes: 4 additions & 1 deletion modules/signals/src/patch-state.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { STATE_SIGNAL, StateSignal } from './state-signal';
import { Prettify } from './ts-helpers';

export type PartialStateUpdater<State extends object> = (
state: State
) => Partial<State>;

export function patchState<State extends object>(
stateSignal: StateSignal<State>,
...updaters: Array<Partial<State & {}> | PartialStateUpdater<State & {}>>
...updaters: Array<
Partial<Prettify<State>> | PartialStateUpdater<Prettify<State>>
>
): void {
stateSignal[STATE_SIGNAL].update((currentState) =>
updaters.reduce(
Expand Down

0 comments on commit 6b440ee

Please sign in to comment.