@gjv/redux-slice-factory
Version:
Generic factory functions for common slice data structures
345 lines (319 loc) • 14.8 kB
TypeScript
import { CaseReducer } from '@reduxjs/toolkit';
import { CaseReducerActions } from '@reduxjs/toolkit';
import { Comparer } from '@reduxjs/toolkit';
import { Draft } from '@reduxjs/toolkit';
import { EntityId } from '@reduxjs/toolkit';
import { EntitySelectors } from '@reduxjs/toolkit';
import { EntityState } from '@reduxjs/toolkit';
import { OutputSelector } from '@reduxjs/toolkit';
import { PayloadAction } from '@reduxjs/toolkit';
import { Reducer } from '@reduxjs/toolkit';
import { Selector } from '@reduxjs/toolkit';
import { SerializedError } from '@reduxjs/toolkit';
import { SliceCaseReducers } from '@reduxjs/toolkit';
import { Update } from '@reduxjs/toolkit';
/**
* @public
*/
export declare function createEntitySlice<TGlobalState, TEntity, TStatusEnum extends keyof typeof StatusEnum | string = keyof typeof StatusEnum, TError extends SerializedError = SerializedError>(options: ICreateEntitySliceOptions<TGlobalState, TEntity, TStatusEnum, TError>): IEntitySlice<TGlobalState, TEntity, TStatusEnum, TError>;
/**
* @public
*/
export declare function createModelSlice<TGlobalState, TModel, TStatusEnum extends keyof typeof StatusEnum | string = keyof typeof StatusEnum, TError extends SerializedError = SerializedError>(options: ICreateModelSliceOptions<TGlobalState, TModel, TStatusEnum, TError>): IModelSlice<TGlobalState, TModel, TStatusEnum, TError>;
/**
* @public
*/
export declare interface ICreateEntitySliceOptions<TGlobalState, TEntity, TStatusEnum extends keyof typeof StatusEnum | string = keyof typeof StatusEnum, TError extends SerializedError = SerializedError> extends ISliceOptions<TGlobalState, IEntityState<TEntity, TStatusEnum, TError>> {
selectId: (o: TEntity) => EntityId;
sortComparer: false | Comparer<TEntity>;
}
/**
* @public
*/
export declare interface ICreateModelSliceOptions<TGlobalState, TModel, TStatusEnum extends keyof typeof StatusEnum | string = keyof typeof StatusEnum, TError extends SerializedError = SerializedError> extends ISliceOptions<TGlobalState, IModelState<TModel, TStatusEnum, TError>> {
/**
* This is how the slice will merge the current model and the update model during an update action
* @defaultValue `merge` from {@link https://www.npmjs.com/package/ts-deepmerge}
*/
handleUpdate?: (current: Draft<TModel>, update: Partial<TModel>) => TModel;
}
/**
* @public
*/
export declare type IEntitySlice<TGlobalState, TEntity, TStatusEnum extends keyof typeof StatusEnum | string = keyof typeof StatusEnum, TError extends SerializedError = SerializedError> = ISlice<TGlobalState, IEntityState<TEntity, TStatusEnum, TError>, IEntitySliceReducers<IEntityState<TEntity, TStatusEnum, TError>, TEntity, TStatusEnum, TError>, IEntitySliceSelectors<TGlobalState, TEntity, TStatusEnum, TError>>;
/**
* @public
*/
export declare interface IEntitySliceReducers<TSliceState, TEntity, TStatusEnum extends keyof typeof StatusEnum | string = keyof typeof StatusEnum, TError extends SerializedError = SerializedError> extends IMetaSliceReducers<TSliceState, TStatusEnum, TError> {
/**
* This will modify the slice. This adds one entity to the slice and sets lastModified.
* @see {@link @reduxjs/toolkit#EntityStateAdapter}
*/
addOne: CaseReducer<TSliceState, PayloadAction<TEntity>>;
/**
* This will modify the slice. This adds many entities to the slice and sets lastModified.
* @see {@link @reduxjs/toolkit#EntityStateAdapter}
*/
addMany: CaseReducer<TSliceState, PayloadAction<Array<TEntity> | Record<EntityId, TEntity>>>;
/**
* This will hydrate the slice. This sets one entity of the slice and lastHydrated, and resets lastModified.
* @see {@link @reduxjs/toolkit#EntityStateAdapter.setOne}
*/
hydrateOne: CaseReducer<TSliceState, PayloadAction<TEntity>>;
/**
* This will hydrate the slice. This sets many entities of the slice and lastHydrated, and resets lastModified.
* @see {@link @reduxjs/toolkit#EntityStateAdapter.setMany}
*/
hydrateMany: CaseReducer<TSliceState, PayloadAction<Array<TEntity> | Record<EntityId, TEntity>>>;
/**
* This will hydrate the slice. This sets all entities of the slice and lastHydrated, and resets lastModified.
* @see {@link @reduxjs/toolkit#EntityStateAdapter.setAll}
*/
hydrateAll: CaseReducer<TSliceState, PayloadAction<Array<TEntity> | Record<EntityId, TEntity>>>;
/**
* This will modify the slice. This updates one entity of the slice and sets lastModified.
* @see {@link @reduxjs/toolkit#EntityStateAdapter.updateOne}
*/
updateOne: CaseReducer<TSliceState, PayloadAction<Update<TEntity>>>;
/**
* This will modify the slice. This updates many entities of the slice and sets lastModified.
* @see {@link @reduxjs/toolkit#EntityStateAdapter.updateMany}
*/
updateMany: CaseReducer<TSliceState, PayloadAction<Array<Update<TEntity>>>>;
/**
* This will modify the slice. This updates or inserts one entity of the slice and sets lastModified.
* @see {@link @reduxjs/toolkit#EntityStateAdapter.upsertOne}
*/
upsertOne: CaseReducer<TSliceState, PayloadAction<TEntity>>;
/**
* This will modify the slice. This updates or inserts many entities of the slice and sets lastModified.
* @see {@link @reduxjs/toolkit#EntityStateAdapter.upsertMany}
*/
upsertMany: CaseReducer<TSliceState, PayloadAction<Array<TEntity> | Record<EntityId, TEntity>>>;
/**
* This will modify the slice. This removes one entity of the slice and sets lastModified.
* @see {@link @reduxjs/toolkit#EntityStateAdapter.removeOne}
*/
removeOne: CaseReducer<TSliceState, PayloadAction<EntityId>>;
/**
* This will modify the slice. This removes many entities of the slice and sets lastModified.
* @see {@link @reduxjs/toolkit#EntityStateAdapter.removeMany}
*/
removeMany: CaseReducer<TSliceState, PayloadAction<Array<EntityId>>>;
/**
* This will modify the slice. This removes all entities of the slice and sets lastModified.
* @see {@link @reduxjs/toolkit#EntityStateAdapter.removeAll}
*/
removeAll: CaseReducer<TSliceState, PayloadAction>;
/**
* This will reset the slice to its initial state.
*/
reset: CaseReducer<TSliceState, PayloadAction>;
/**
* This will modify the slice. This sets all entities of the slice and sets lastModified.
* @see {@link @reduxjs/toolkit#EntityStateAdapter.setAll}
*/
setAll: CaseReducer<TSliceState, PayloadAction<Array<TEntity> | Record<EntityId, TEntity>>>;
}
/**
* @public
*/
export declare interface IEntitySliceSelectors<TGlobalState, TEntity, TStatusEnum extends keyof typeof StatusEnum | string = keyof typeof StatusEnum, TError extends SerializedError = SerializedError> extends EntitySelectors<TEntity, TGlobalState>, ISliceSelectors<TGlobalState, IEntityState<TEntity, TStatusEnum, TError>>, IMetaSliceSelectors<TGlobalState, IEntityState<TEntity, TStatusEnum, TError>, TStatusEnum, TError> {
}
/**
* @public
*/
export declare interface IEntityState<T, TStatusEnum extends keyof typeof StatusEnum | string = keyof typeof StatusEnum, TError extends SerializedError = SerializedError> extends EntityState<T>, IMetaState<TStatusEnum, TError> {
}
declare interface IMetaSliceReducers<TSliceState, TStatusEnum extends keyof typeof StatusEnum | string = keyof typeof StatusEnum, TError extends SerializedError = SerializedError> extends SliceCaseReducers<TSliceState> {
/**
* This will set the status of the slice.
*/
setStatus: CaseReducer<TSliceState, PayloadAction<TStatusEnum>>;
/**
* This will set the error of the slice.
*/
setError: CaseReducer<TSliceState, PayloadAction<TError | null>>;
/**
* This will set any meta state properties that are defined
*/
setMetaState: CaseReducer<TSliceState, PayloadAction<Partial<Pick<IMetaState<TStatusEnum, TError>, 'error' | 'status'>>>>;
}
/**
* @public
* @see IMetaState
*/
export declare interface IMetaSliceSelectors<TGlobalState, TSliceState, TStatusEnum extends keyof typeof StatusEnum | string = keyof typeof StatusEnum, TError extends SerializedError = SerializedError> {
/**
* This selects the status of the slice.
* @see {@link IMetaState.status}
*/
selectStatus: IOutputSelector<TGlobalState, TSliceState, TStatusEnum>;
/**
* This selects the error of the slice.
* @see {@link IMetaState.error}
*/
selectError: IOutputSelector<TGlobalState, TSliceState, TError | null>;
/**
* This selects the lastModified of the slice.
* @see {@link IMetaState.lastModified}
*/
selectLastModified: IOutputSelector<TGlobalState, TSliceState, string | null>;
/**
* This selects the status of the slice.
* @see {@link IMetaState.lastHydrated}
*/
selectLastHydrated: IOutputSelector<TGlobalState, TSliceState, string | null>;
}
/**
* @public
*/
export declare interface IMetaState<TStatusEnum extends keyof typeof StatusEnum | string = keyof typeof StatusEnum, TError extends SerializedError = SerializedError> {
/**
* The status of the slice.
* @defaultValue `StatusEnum`
*/
status: TStatusEnum;
/**
* The status of the slice.
* @defaultValue `SerializedError`
*/
error: TError | null;
/**
* The timestamp of the last time the slice was modified.
*/
lastModified: string | null;
/**
* The timestamp of the last time the slice was hydrated.
*/
lastHydrated: string | null;
}
/**
* @public
*/
export declare type IModelSlice<TGlobalState, TModel, TStatusEnum extends keyof typeof StatusEnum | string = keyof typeof StatusEnum, TError extends SerializedError = SerializedError> = ISlice<TGlobalState, IModelState<TModel, TStatusEnum, TError>, IModelSliceReducers<IModelState<TModel, TStatusEnum, TError>, TModel, TStatusEnum, TError>, IModelSliceSelectors<TGlobalState, TModel, TStatusEnum, TError>>;
/**
* @public
*/
export declare interface IModelSliceReducers<TSliceState, TModel, TStatusEnum extends keyof typeof StatusEnum | string = keyof typeof StatusEnum, TError extends SerializedError = SerializedError> extends IMetaSliceReducers<TSliceState, TStatusEnum, TError> {
/**
* This will hydrate the slice. This sets the model and lastHydrated, and resets lastModified.
*/
hydrate: CaseReducer<TSliceState, PayloadAction<TModel>>;
/**
* This will modify the slice. This updates the model and sets lastModified.
*/
update: CaseReducer<TSliceState, PayloadAction<Partial<TModel>>>;
/**
* This will modify the slice. This sets the model and sets lastModified.
*/
set: CaseReducer<TSliceState, PayloadAction<TModel>>;
/**
* This will reset the slice to its initial state.
*/
reset: CaseReducer<TSliceState, PayloadAction>;
}
/**
* @public
*/
export declare interface IModelSliceSelectors<TGlobalState, TModel, TStatusEnum extends keyof typeof StatusEnum | string = keyof typeof StatusEnum, TError extends SerializedError = SerializedError> extends ISliceSelectors<TGlobalState, IModelState<TModel, TStatusEnum, TError>>, IMetaSliceSelectors<TGlobalState, IModelState<TModel, TStatusEnum, TError>, TStatusEnum, TError> {
/**
* This selects the slice model.
*/
selectModel: IOutputSelector<TGlobalState, IModelState<TModel, TStatusEnum, TError>, TModel>;
}
/**
* @public
*/
export declare interface IModelState<T, TStatusEnum extends keyof typeof StatusEnum | string = keyof typeof StatusEnum, TError extends SerializedError = SerializedError> extends IMetaState<TStatusEnum, TError> {
/**
* The model of the slice.
*/
model: T;
}
/**
* @public
*/
declare type IOutputSelector<TGlobalState, TSliceState, TResult> = OutputSelector<[Selector<TGlobalState, TSliceState>], TResult, (sliceState: TSliceState) => TResult>;
/**
* @public
*/
declare type ISelectCanRequest<TSliceState> = (sliceState: TSliceState) => boolean;
/**
* @public
*/
declare type ISelectShouldRequest<TSliceState> = (sliceState: TSliceState, canRequest: ReturnType<ISelectCanRequest<TSliceState>>) => boolean;
/**
* @public
*/
declare type ISelectSliceState<TGlobalState, TSliceState> = (globalState: TGlobalState) => TSliceState;
/**
* @public
*/
export declare interface ISlice<TGlobalState, TSliceState, TCaseReducers extends SliceCaseReducers<TSliceState>, TSliceSelectors extends ISliceSelectors<TGlobalState, TSliceState>> {
name: ISliceName<TGlobalState>;
reducer: Reducer<TSliceState>;
actions: CaseReducerActions<TCaseReducers>;
selectors: TSliceSelectors;
}
/**
* @internal
*/
declare type ISliceName<TGlobalState> = keyof TGlobalState & string;
/**
* @public
*/
declare interface ISliceOptions<TGlobalState, TSliceState> {
/**
* The name of the slice in the redux store.
*/
name: ISliceName<TGlobalState>;
/**
* @see {@link ISliceSelectors.selectSliceState}
*/
selectSliceState: ISelectSliceState<TGlobalState, TSliceState>;
/**
* @see {@link ISliceSelectors.selectCanRequest}
*/
selectCanRequest?: ISelectCanRequest<TSliceState>;
/**
* @see {@link ISliceSelectors.selectShouldRequest}
*/
selectShouldRequest?: ISelectShouldRequest<TSliceState>;
/**
* The initial state of the slice.
*/
initialState?: Partial<TSliceState>;
/**
* The function for mapping a `Date` to a timestamp.
*/
createTimestamp?: (datetime?: Date) => string;
}
/**
* @public
*/
export declare interface ISliceSelectors<TGlobalState, TSliceState> {
/**
* @public
* Selects the entire slice state.
*/
selectSliceState: IOutputSelector<TGlobalState, TSliceState, TSliceState>;
/**
* @defaultValue (overrideable) The slice can request if it is not requesting, error is empty, and the slice has not been modified
*/
selectCanRequest: IOutputSelector<TGlobalState, TSliceState, boolean>;
/**
* @defaultValue (overrideable) The slice should request if it can request and it has not been hydrated
* @see {@link ISliceSelectors.selectCanRequest}
*/
selectShouldRequest: IOutputSelector<TGlobalState, TSliceState, boolean>;
}
/**
* @public
*/
export declare enum StatusEnum {
Settled = "Settled",
Requesting = "Requesting",
Failed = "Failed"
}
export { }