UNPKG

@rbxts/create-slice

Version:

Helpful function to easily define rodux reducers.

141 lines (127 loc) 4.13 kB
import Rodux from "@rbxts/rodux" import { Equals, Extends, If, IsAny } from "./utils/utils" /** * Infer the return type of a CaseReducer */ type InferReturnType<T> = T extends CaseReducer<any, any, infer R> ? R : never /** * Rodux action with a generic payload property. If the payload's type is void, Rodux.AnyAction will be used instead. */ export type PayloadAction<Payload> = If< Equals<Payload, void>, Rodux.AnyAction, Rodux.Action & { payload: Payload } > /** * Options for `createSlice` */ export interface CreateSliceOptions< State, Name extends string, CaseReducers extends SliceCaseReducers<State>, > { /** * The slice's name. Used to namespace the generated action types. */ name: Name /** * The initial state that should be used when the reducer is called the first time. * This may also be a "lazy initializer" function, which should return an initial state value when called. * This will be used whenever the reducer is called with `undefined` as its state value. */ initialState: State | (() => State) /** * A mapping from action types to action-type-specific *case reducer* functions. * For every action type, a matching action creator will be generated using `makeActionCreator()`. */ reducers: CaseReducers } /** * The return value of `createSlice */ export interface Slice< State, Name extends string = string, CaseReducers extends SliceCaseReducers<State> = SliceCaseReducers<State>, > { /** * The slice's name. */ name: Name /** * The slice's reducer. */ reducer: SliceReducer<State, Name, CaseReducers> /** * The individual case reducer functions that were passed in the `reducers` parameter. * This enables reuse and testing if they were defined inline when calling `createSlice`. */ caseReducers: ValidateCaseReducers<State, CaseReducers> /** * Action creators for the types of actions that are handled by the slice reducer. */ actions: CaseReducerActionCreators<Name, CaseReducers> } /** * Case Reducers */ export type CaseReducer<State, Payload = any, Return extends State | void = State | void> = ( this: void, state: State, payload: PayloadAction<Payload>, ) => Return export type SliceCaseReducers<State, Payload = any> = Record<string, CaseReducer<State, Payload>> /** * Assign each case reducer to the CaseReducer type. Without this, defining a reducer * as `(state) => {}` would infer action to PayloadAction<unknown> instead of PayloadAction<void> */ type ValidateCaseReducers<S, ACR extends SliceCaseReducers<S>> = { [K in keyof ACR]: If< Extends<Parameters<ACR[K]>["length"], 0 | 1>, CaseReducer<S, void, InferReturnType<ACR[K]>>, // 0-1 params means no action param ACR[K] extends CaseReducer<S, infer P, infer R> ? If<IsAny<P>, CaseReducer<S, any, R>, CaseReducer<S, P, R>> : never > } /** * Creates a Rodux ActionCreator for a given CaseReducer */ type MakeCaseAction<N extends string, CR extends CaseReducer<any, any>> = If< Extends<Parameters<CR>["length"], 0 | 1>, Rodux.ActionCreator<N, [], {}>, CR extends CaseReducer<any, infer P> ? If< IsAny<P>, Rodux.ActionCreator<N, [payload?: any], { payload: any }>, Rodux.ActionCreator<N, [payload: P], { payload: P }> > : never > /** * Combines the name of a slice with the name of an action with a "/" between them. */ type SliceActionName<SliceName extends string, ActionName extends keyof any> = ActionName extends | string | number ? `${SliceName}/${ActionName}` : string /** * Creates a union of all Rodux Actions for a group of caseReducers */ type SliceReducerActions<N extends string, ACR extends SliceCaseReducers<any>> = { [K in keyof ACR]: ReturnType<MakeCaseAction<SliceActionName<N, K>, ACR[K]>> }[keyof ACR] /** * The slice's reducer */ type SliceReducer<S, N extends string, ACR extends SliceCaseReducers<S>> = Rodux.Reducer< S, SliceReducerActions<N, ACR> > /** * Creates an interface with a Rodux ActionCreator for each caseReducer */ type CaseReducerActionCreators<N extends string, ACR extends SliceCaseReducers<any>> = { [K in keyof ACR]: MakeCaseAction<SliceActionName<N, K>, ACR[K]> }