Reputation: 605
Info: Using Typescript 3.3.3333 in Jetbrains Rider
Given this type definition of Reducer<State, Action>
:
* @template S The type of state consumed and produced by this reducer.
* @template A The type of actions the reducer can potentially respond to.
*/
export type Reducer<S = any, A extends Action = AnyAction> = (
state: S | undefined,
action: A
) => S
Why will the return type of S
not type check the state I am returning from the reducer, unless I define it explicitly?
export const INITIAL_STATE: AuthenticationState = {
authenticationInProgress: false,
accessToken: null,
tokenType: null,
expiryTimeMs: null,
errorInformation: null,
isAdmin: false,
};
export const authenticationReducer: Reducer<AuthenticationState,
AuthenticationActions> = (state = INITIAL_STATE, action):
(why is this necessary??) -> AuthenticationState => {
switch (action.type) {
case "authentication/user_authentication_request": {
return {
...state,
problem -> hello: "hi",
authenticationInProgress: true,
};
}
...
Behavior I expect without needing to define AuthenticationState as the return value
VS.
Why is there no more type checking on the return value if the Reducer Type includes the return value of S?
Any light shedding and wisdom is really welcome. Thanks in advance.
Upvotes: 1
Views: 138
Reputation: 14179
as Christian Santos stated, this is the expected behaviour.
If you want to have a type safe redux experience, then I suggest you to have a look at some redux extension that has been designed with that in mind!
check out redux-fluent
Upvotes: 0
Reputation: 5456
TLDR: This is the expected behavior in TypeScript due to how excess property checking works.
In your case, the arrow function you define has a return type that has excess (or extra) properties. To TypeScript, that's completely OK.
In a simplified example, take a look at this behavior:
type a = () => { a: string };
type b = () => { a: string, b: string };
declare let myA: a;
declare let myB: b;
myA = myB; // OK! (excess properties are not checked)
myB = myA; // Error: missing required property 'b'
At the crux of your issue is that you're essentially assigning myB
to myA
and expecting an error, but you'll only get an error when assigning myA
to myB
.
You have a few options to make your code work as expected (such as the one you've proposed, where you explicitly define the return type), but none of them are ideal until TypeScript supports exact types (there's an open issue for exact types that discusses your exact use case w/ redux and some workarounds).
Upvotes: 1