Skip to content

Commit

Permalink
fix(store): 🐞 improve state type
Browse files Browse the repository at this point in the history
βœ… Closes: #510
  • Loading branch information
NetanelBasal committed Feb 3, 2024
1 parent 7dd238c commit ee784a4
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 20 deletions.
13 changes: 2 additions & 11 deletions packages/store/src/lib/create-store.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
import { createState, PropsFactory } from './state';
import { createState, Merge, PropsFactory } from './state';
import { Store } from './store';

type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never;
type Merge<State extends any[], Key extends PropertyKey> = UnionToIntersection<
State[number][Key]
>;

export function createStore<
S extends [PropsFactory<any, any>, ...PropsFactory<any, any>[]]
S extends [PropsFactory<any, any>, ...PropsFactory<any, any>[]],
>(
storeConfig: StoreConfig,
...propsFactories: S
Expand Down
14 changes: 6 additions & 8 deletions packages/store/src/lib/state.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never;
type Merge<State extends any[], Key extends PropertyKey> = UnionToIntersection<
State[number][Key]
>;
export type Merge<
State extends Record<Key, any>[],
Key extends PropertyKey,
> = State extends [Record<Key, infer V>, ...infer Rest extends any[]]
? V & Merge<Rest, Key>
: unknown;

export type PropsFactory<Props, Config> = { props: Props; config: Config };
export type EmptyConfig = undefined;
Expand Down
19 changes: 18 additions & 1 deletion packages/store/src/lib/types.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('Store types', () => {
it('should set the correct types', () => {
const { state, config } = createState(
withProps<Props>({ id: 1, name: 'foo' }),
withFoo()
withFoo(),
);

expectTypeOf(state).toEqualTypeOf<Props & FooProps>();
Expand Down Expand Up @@ -67,4 +67,21 @@ describe('Store types', () => {
//
}
});

it('should work with union types', () => {
type Circle = { kind: 'CIRCLE'; diameter: number };
type Square = { kind: 'SQUARE'; edge: number };
type Shape = Circle | Square;

const v1 = createState(
withProps<Shape>({ kind: 'CIRCLE', diameter: 2 }),
withProps<{ id: number }>({ id: 1 }),
);

expectTypeOf(v1.state).toEqualTypeOf<Shape & { id: number }>();

const v2 = createState(withProps<Shape>({ kind: 'CIRCLE', diameter: 2 }));

expectTypeOf(v2.state).toEqualTypeOf<Shape>();
});
});

0 comments on commit ee784a4

Please sign in to comment.