mirror of
https://github.com/pybricks/pybricks-code.git
synced 2026-09-12 01:23:52 +00:00
76 lines
2.5 KiB
TypeScript
76 lines
2.5 KiB
TypeScript
// SPDX-License-Identifier: MIT
|
|
// Copyright (c) 2022 The Pybricks Authors
|
|
|
|
import { AnyAction } from 'redux';
|
|
|
|
/** A function that creates action objects. */
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
type ActionCreationFunction<A extends AnyAction> = (...args: any[]) => A;
|
|
|
|
/** A function that performs type discrimination on an action. */
|
|
type MatchFunction<A extends AnyAction> = (action: AnyAction) => action is A;
|
|
|
|
/** The extra members that are attached to a function by createAction(). */
|
|
type MatchableExtensions<F extends ActionCreationFunction<A>, A extends AnyAction> = {
|
|
/**
|
|
* This should not usually be used directly. It allows Matchable action
|
|
* functions to be passed directly to redux saga effects as an action pattern.
|
|
*/
|
|
toString(): ReturnType<F>['type'];
|
|
/**
|
|
* Type guard to ensure an action matches this type.
|
|
*/
|
|
matches: MatchFunction<ReturnType<F>>;
|
|
/**
|
|
* Type guard creation function with addition filtering.
|
|
*
|
|
* This is useful for creating a guard function to pass to redux saga
|
|
* effects.
|
|
*
|
|
* @example const action = yield* take(someAction.when((a) => a.property === value));
|
|
*
|
|
* @param predicate An predicate to filter actions.
|
|
*/
|
|
when(predicate: (action: ReturnType<F>) => boolean): MatchFunction<ReturnType<F>>;
|
|
};
|
|
|
|
/** An action creation function that includes MatchableExtensions. */
|
|
type Matchable<F extends ActionCreationFunction<A>, A extends AnyAction> = F &
|
|
MatchableExtensions<F, A>;
|
|
|
|
/**
|
|
* Adds additional members to an action creation function.
|
|
*
|
|
* @param actionCreator The action creation function.
|
|
* @returns actionCreator with type property and match method added.
|
|
*/
|
|
export function createAction<
|
|
F extends ActionCreationFunction<A>,
|
|
A extends AnyAction = ReturnType<F>,
|
|
>(actionCreator: F): Matchable<F, A> {
|
|
// create a default action so we can get the type string.
|
|
const type = actionCreator().type;
|
|
|
|
function matches(action: AnyAction): action is ReturnType<F> {
|
|
return action.type === type;
|
|
}
|
|
|
|
function when(
|
|
predicate: (action: ReturnType<F>) => boolean,
|
|
): MatchFunction<ReturnType<F>> {
|
|
return (a: AnyAction): a is ReturnType<F> => {
|
|
if (!matches(a)) {
|
|
return false;
|
|
}
|
|
|
|
return predicate(a);
|
|
};
|
|
}
|
|
|
|
return Object.assign(actionCreator, <MatchableExtensions<F, A>>{
|
|
toString: () => type,
|
|
matches,
|
|
when,
|
|
});
|
|
}
|