redux-act
redux-act copied to clipboard
Typescript: Handler not returning state
Hi there, first issue here.
These days using redux-act, I found that the handler of reducer.on
isn't using state
type received in createReducer
.
Example:
interface State {
loading: boolean;
name?: string;
office?: office;
claims?: Array<Claim>;
}
const reducer = createReducer<State>({}, initialState);
reducer.on(loading, (state, payload) => ({
...state,
loading: payload,
foo: 'bar',
}));
foo: 'bar'
isn't in my interface, and don't throw an error in my typings.
It only works when I explict use State
interface as result of my handler function.
Example:
reducer.on(loading, (state, payload): State => ({
...state,
loading: payload,
foo: 'bar',
}));
Only this way I got the expected behaviour:
src/modules/user.ts|31 col 3 error| 2322[QF available]: Type '{ loading: boolean; foo: string; name?: string | undefined; escritorio?: Escritorio | undefined; claims?: Claim[] | undefined; }' is not assignable to type 'State'. Object literal may only specify known properties, and 'foo' does not exist in type 'State'.
I can reproduce but I have no idea why it's failing to type properly. I'm not a huge TypeScript user myself unfortunately.
// This is the signature of the `on` function. 2nd argument is a Handler<S, P, M>
on<Arg1, P, M={}>(actionCreator: ActionCreatorOrString1<Arg1, P, M>, handler: Handler<S, P, M>): Reducer<S>
// This is the type for a Handler, a function that must return a `S`,
// where `S` is the `State` during `createReducer`
type Handler<S, P, M={}> = (state: S, payload: P, meta?: M) => S
export function createReducer<S>(handlers: Handlers<S> | OnOff<S>, defaultState?: S): Reducer<S>;
This seems to be related to type widening issue. The return value is inferred therefore it allows excess properties on the object.
Here's the issue filed with TS: https://github.com/microsoft/TypeScript/issues/241 PR: https://github.com/microsoft/TypeScript/pull/40311 - This didn't land in any version Heres the playground
Unfortunately, there's nothing you can do dynamically and just have to annotate the handler function manually.