Skip to content

Instantly share code, notes, and snippets.

@dht
Created January 31, 2021 20:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dht/40b1b0297203846974c517185b514637 to your computer and use it in GitHub Desktop.
Save dht/40b1b0297203846974c517185b514637 to your computer and use it in GitHub Desktop.
redux store generator
import { StoreStructure, Actions } from './types';
type AppState = { isLoading: boolean; email?: string };
type Task = { id: string; title: string };
type Tasks = Record<string, Task>;
type Log = { id: string };
type Logs = Array<Log>;
interface MyStore extends StoreStructure {
appState: AppState;
tasks: Tasks;
logs: Logs;
}
type MyActions = Actions<MyStore>;
let x: MyActions;
// ============ OK =============
x.appState.patch({ isLoading: false });
x.appState.setAll({ isLoading: true, email: '' });
x.tasks.setAll({ '1': { id: '1', title: '' } });
x.tasks.delete('1');
x.logs.setAll([{ id: '1' }]);
x.logs.push({ id: '1' });
x.logs.pop();
x.logs.clear();
x.tasks.add({ id: '1', title: '1' });
x.tasks.set('1', { id: '1' });
x.tasks.patch('1', { id: '1' });
// ========== PROBLEM ===========
x.appState.patch({ isLoading: false, u: '' }); // unknown field
x.appState.setAll({ isLoading: true, u: '' }); // unknown field
x.tasks.setAll({ '1': { title: '' } }); // id missing
x.tasks.delete(4); // invalid type
x.logs.setAll([{ id: '1', u: '' }]); // unknown field
x.logs.push({ id: '1', u: '' }); // unknown field
x.logs.pop({}); // redundant parameter
x.logs.clear([]); // redundant parameter
x.tasks.add({ title: '', u: '' }); // unknown field
x.tasks.set('1', { u: '' }); // missing id
x.tasks.patch('1', { u: '' }); // unknown field
export enum NodeTypes {
SINGLE_NODE = 'SINGLE_NODE',
COLLECTION_NODE = 'COLLECTION_NODE',
QUEUE_NODE = 'QUEUE_NODE',
}
export type Value = number | boolean | string | null | undefined;
export type Item = { [fieldName: string]: Value } & { id: string };
export type SingleNode = Record<string, any>;
export type CollectionNode = Record<string, Item>;
export type QueueNode = Item[];
export type StoreNode = SingleNode | CollectionNode | QueueNode; // prettier-ignore
export type StoreStructure = Record<string, StoreNode>;
export type Action = {
type: string;
payload: Record<string, any>;
};
export type ActionCreatorId = (id: string) => Action;
export type ActionCreatorPayload<T extends {}> = (payload: T) => Action;
export type ActionCreatorIdAndPayload<T extends {}> = (id: string, payload: T) => Action; // prettier-ignore
export type ActionCreatorEmpty = () => Action;
export type SingleBag<T> = {
patch: ActionCreatorPayload<Partial<T>>;
setAll: ActionCreatorPayload<T>;
};
export type QueueBag<T> = {
setAll: ActionCreatorPayload<T[]>;
push: ActionCreatorPayload<T>;
pop: ActionCreatorEmpty;
clear: ActionCreatorEmpty;
};
export type CollectionBag<T> = {
setAll: ActionCreatorPayload<Record<string, T>>;
add: ActionCreatorPayload<Partial<T>>;
set: ActionCreatorIdAndPayload<Partial<T> & { id: string }>;
patch: ActionCreatorIdAndPayload<Partial<T>>;
delete: ActionCreatorId;
};
export type ActionBag = SingleBag<any> | QueueBag<any> | CollectionBag<any>;
type InferArrayType<T> = T extends Array<infer P> ? P : never;
type InferCollectionType<T> = T extends Record<string, infer P> ? P : never;
export type Actions<StoreStructure> = {
[K in keyof StoreStructure]: StoreStructure[K] extends QueueNode
? QueueBag<InferArrayType<StoreStructure[K]>>
: StoreStructure[K] extends CollectionNode
? CollectionBag<InferCollectionType<StoreStructure[K]>>
: SingleBag<StoreStructure[K]>;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment