Skip to content

Commit

Permalink
Updates typescript definitions to play a _bit_ nicer with generic mod…
Browse files Browse the repository at this point in the history
…el interfaces
  • Loading branch information
ctrlplusb committed Jun 28, 2019
1 parent a0e696f commit f526916
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 5 deletions.
13 changes: 8 additions & 5 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,9 @@ type FilterStateTypes<T extends object> = Overwrite<
* type OnlyActions = Actions<Model>;
*/
export type Actions<Model extends Object> = {
[P in keyof FilterActionTypes<
Pick<Model, KeysOfType<Model, object>>
[P in keyof Overwrite<
FilterActionTypes<Pick<Model, KeysOfType<Model, object>>>,
Pick<Model, KeysOfType<Model, ActionTypes>>
>]: Model[P] extends Thunk<any, any, any, any, infer R>
? Param1<Model[P]> extends void
? () => R extends Promise<any> ? R : Promise<R>
Expand All @@ -108,7 +109,9 @@ export type Actions<Model extends Object> = {
? Param1<Model[P]> extends void
? () => void
: (payload: Param1<Model[P]>) => void
: Actions<Model[P]>;
: Model[P] extends object
? Actions<Model[P]>
: unknown;
};

type RequiredOnly<Model extends Object> = Pick<Model, RequiredKeys<Model>>;
Expand Down Expand Up @@ -136,11 +139,11 @@ type RecursiveState<
RequiredModel extends Object,
OptionalModel extends Object
> = Overwrite<
{ [P in keyof OtherModel]: OtherModel[P] },
Overwrite<
{ [P in keyof RequiredModel]: StateModelValues<RequiredModel, P> },
{ [P in keyof OptionalModel]?: StateModelValues<OptionalModel, P> }
>
>,
{ [P in keyof OtherModel]: OtherModel[P] }
>;

type FilterIndexSignatures<
Expand Down
81 changes: 81 additions & 0 deletions src/__tests__/typescript/issue224.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/* eslint-disable */

import {
createStore,
computed,
Computed,
action,
Action,
thunk,
Thunk,
} from 'easy-peasy';

interface ObjectWithId {
id: number;
}

interface Nested {
save: Thunk<Nested>;
}

interface DataModel<DataItem extends ObjectWithId> {
data: { [key: number]: DataItem };
sortBy: keyof DataItem | 'none';
ids: Computed<DataModel<DataItem>, string[]>;
fetched: Action<DataModel<DataItem>, DataItem[]>;
fetch: Thunk<DataModel<DataItem>, string>;
getItemById: Computed<
DataModel<DataItem>,
(id: number) => DataItem | undefined
>;
nested: Nested;
}

const dataModel = <Item extends ObjectWithId>(
endpoint: () => Promise<Item[]>,
): DataModel<Item> => {
const result: DataModel<Item> = {
data: {},
ids: computed(state => Object.keys(state.data)),
fetched: action((state, items) => {
items.forEach((item, idx) => {
state.data[idx] = item;
});
84656;
}),
fetch: thunk(async (actions, payload) => {
const data = await endpoint();
actions.fetched(data);
// Nested actions do not work on generics :(
// typings:expect-error
actions.nested.save();
}),
getItemById: computed(state => (id: number) =>
Object.values(state.data).find(item => item.id === id),
),
sortBy: 'id',
nested: {
save: thunk(() => {}),
},
};
return result;
};

interface Person extends ObjectWithId {
id: number;
name: string;
}

const personModel = dataModel<Person>(() =>
Promise.resolve([{ id: 1, name: 'bob' }]),
);

const store = createStore(personModel);

store.getState().sortBy;

store.getActions().fetched([]);
store.getActions().data;
// typings:expect-error
store.getActions().sortBy;
store.getActions().nested.save();

0 comments on commit f526916

Please sign in to comment.