Skip to content

Commit

Permalink
fix(store): allow union of types in props (#2301)
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-okrushko authored and brandonroberts committed Jan 10, 2020
1 parent 711c30d commit 33241cb
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 22 deletions.
22 changes: 22 additions & 0 deletions modules/store/spec/action_creator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,28 @@ describe('Action Creators', () => {
narrow(foo({ foo: 42 }));
});

it('should allow the union of types in props', () => {
interface A {
sameProp: 'A';
}
interface B {
sameProp: 'B';
extraProp: string;
}
type U = A | B;
const foo = createAction('FOO', props<U>());

const fooA = foo({ sameProp: 'A' });
const fooB = foo({ sameProp: 'B', extraProp: 'allowed' });

expect(fooA).toEqual({ type: 'FOO', sameProp: 'A' });
expect(fooB).toEqual({
type: 'FOO',
sameProp: 'B',
extraProp: 'allowed',
});
});

it('should be serializable', () => {
const foo = createAction('FOO', props<{ foo: number }>());
const fooAction = foo({ foo: 42 });
Expand Down
16 changes: 7 additions & 9 deletions modules/store/src/action_creator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import {
ActionCreator,
TypedAction,
FunctionWithParametersType,
PropsReturnType,
DisallowArraysAndTypeProperty,
NotAllowedCheck,
Props,
} from './models';

// Action creators taken from ts-action library and modified a bit to better
Expand All @@ -15,15 +15,15 @@ export function createAction<T extends string>(
): ActionCreator<T, () => TypedAction<T>>;
export function createAction<T extends string, P extends object>(
type: T,
config: { _as: 'props'; _p: P }
): ActionCreator<T, (props: P) => P & TypedAction<T>>;
config: Props<P>
): ActionCreator<T, (props: P & NotAllowedCheck<P>) => P & TypedAction<T>>;
export function createAction<
T extends string,
P extends any[],
R extends object
>(
type: T,
creator: Creator<P, DisallowArraysAndTypeProperty<R>>
creator: Creator<P, R> & NotAllowedCheck<R>
): FunctionWithParametersType<P, R & TypedAction<T>> & TypedAction<T>;
/**
* @description
Expand Down Expand Up @@ -121,10 +121,8 @@ export function createAction<T extends string, C extends Creator>(
}
}

export function props<P extends object>(): PropsReturnType<P> {
// the return type does not match TypePropertyIsNotAllowed, so double casting
// is used.
return ({ _as: 'props', _p: undefined! } as unknown) as PropsReturnType<P>;
export function props<P extends object>(): Props<P> {
return { _as: 'props', _p: undefined! };
}

export function union<
Expand Down
21 changes: 8 additions & 13 deletions modules/store/src/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,6 @@ export const arraysAreNotAllowedMsg =
'arrays are not allowed in action creators';
type ArraysAreNotAllowed = typeof arraysAreNotAllowedMsg;

export type DisallowArraysAndTypeProperty<T> = T extends any[]
? ArraysAreNotAllowed
: T extends { type: any } ? TypePropertyIsNotAllowed : T;

export const typePropertyIsNotAllowedMsg =
'type property is not allowed in action creators';
type TypePropertyIsNotAllowed = typeof typePropertyIsNotAllowedMsg;
Expand All @@ -75,17 +71,11 @@ export type FunctionIsNotAllowed<
export type Creator<
P extends any[] = any[],
R extends object = object
> = R extends any[]
? ArraysAreNotAllowed
: R extends { type: any }
? TypePropertyIsNotAllowed
: FunctionWithParametersType<P, R>;
> = FunctionWithParametersType<P, R>;

export type PropsReturnType<T extends object> = T extends any[]
export type NotAllowedCheck<T extends object> = T extends any[]
? ArraysAreNotAllowed
: T extends { type: any }
? TypePropertyIsNotAllowed
: { _as: 'props'; _p: T };
: T extends { type: any } ? TypePropertyIsNotAllowed : unknown;

/**
* See `Creator`.
Expand All @@ -95,6 +85,11 @@ export type ActionCreator<
C extends Creator = Creator
> = C & TypedAction<T>;

export interface Props<T> {
_as: 'props';
_p: T;
}

export type FunctionWithParametersType<P extends unknown[], R = void> = (
...args: P
) => R;
Expand Down

0 comments on commit 33241cb

Please sign in to comment.