I have a redux style reducer (I'm using ngrx) that is returning a specific type. When I use the spread operator in my return object, the typescript linter is not catching invalid properties.
Here is my interface:
interface MyState {
firstName: string;
lastName: string;
age: number;
}
Here is my reducer. Action is an ngrx action:
function reducer(state = initialState, action: Action): MyState {
switch (action.type) {
case Actions.COOL_ACTION:
return {
...state,
propertyDoesNotExist: action.payload, // <- no error
};
default:
return state;
}
}
I would expect that propertyDoesNotExist would be flagged, but it is not. I've tried casting <CalendarState> the return object, the state property ...(<CalendarState>state) and using the as alias, but it doesn't help.
It's like the spread operator messes up the types.
By using ...state, the returned expression is no longer an object literal, and TypeScript won't complain if it's a subtype of the return type (i.e. has extra properties). I ran into this problem myself and wrote a little helper function to signal extra properties:
const applyChanges = <S, K extends keyof S>(state : S, changes : Pick<S, K>) : S =>
Object.assign({}, state, changes);
(using Object.assign instead of spread operators because of this issue: https://github.com/Microsoft/TypeScript/issues/14409)
To use applyChanges, simply replace
return {...state,
propertyDoesNotExist: action.payload, // <- no error
};
with
return applyChanges(state, {
propertyDoesNotExist: action.payload, // <- error
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With