Skip to content

Instantly share code, notes, and snippets.

@sina-salahshour
Created April 29, 2023 12:17
Show Gist options
  • Select an option

  • Save sina-salahshour/65ff86b6fc02b712921bb66ba15312f8 to your computer and use it in GitHub Desktop.

Select an option

Save sina-salahshour/65ff86b6fc02b712921bb66ba15312f8 to your computer and use it in GitHub Desktop.
redux like store for svelte
import { writable, type Writable } from 'svelte/store';
type Args<T> = T extends (...args: [...infer R]) => void ? R : never;
function createReducer<P>(type: string) {
return function (payload: P) {
return {
type,
payload
};
};
}
export function createStore<
I,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
T extends { [key: string]: (state: Writable<I>, payload?: any) => void }
>({ initialState, reducers }: { initialState: I; reducers: T }) {
const store = writable(initialState);
const returnReducers = Object.fromEntries(
Object.entries(reducers).map(([actionType]) => [actionType, createReducer(actionType)])
);
function dispatch<K extends keyof typeof reducers>({
type,
payload
}: {
type: K;
payload: Args<(typeof reducers)[K]>[1];
}) {
reducers[type](store, payload);
}
return {
dispatch,
store,
reducers: returnReducers as {
[K in keyof typeof reducers]: (payload: Args<(typeof reducers)[K]>[1]) => {
type: K;
payload: typeof payload;
};
},
dispatchReducers: Object.fromEntries(
Object.entries(returnReducers).map(([actionType, reducer]) => [
actionType,
(payload: unknown) => dispatch(reducer(payload))
])
) as {
[K in keyof typeof reducers]: (payload: Args<(typeof reducers)[K]>[1]) => void;
}
};
}
@sina-salahshour
Copy link
Copy Markdown
Author

using immer:

import { writable } from 'svelte/store';
import { produce, type Draft } from 'immer';

type Args<T> = T extends (...args: [...infer R]) => void ? R : never;

function createReducer<P>(type: string) {
	return function (payload: P) {
		return {
			type,
			payload
		};
	};
}

export function createStore<
	I extends object,
	// eslint-disable-next-line @typescript-eslint/no-explicit-any
	T extends { [key: string]: (state: Draft<I>, payload?: any) => void }
>({ initialState, reducers }: { initialState: I; reducers: T }) {
	const store = writable(initialState);
	const returnReducers = Object.fromEntries(
		Object.entries(reducers).map(([actionType]) => [actionType, createReducer(actionType)])
	);
	function dispatch<K extends keyof typeof reducers>({
		type,
		payload
	}: {
		type: K;
		payload: Args<(typeof reducers)[K]>[1];
	}) {
		store.update((state) => produce(state, (draft) => reducers[type](draft, payload)));
	}
	return {
		dispatch,
		store,
		reducers: returnReducers as {
			[K in keyof typeof reducers]: (payload: Args<(typeof reducers)[K]>[1]) => {
				type: K;
				payload: typeof payload;
			};
		},
		dispatchReducers: Object.fromEntries(
			Object.entries(returnReducers).map(([actionType, reducer]) => [
				actionType,
				(payload: unknown) => dispatch(reducer(payload))
			])
		) as {
			[K in keyof typeof reducers]: (payload: Args<(typeof reducers)[K]>[1]) => void;
		}
	};
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment