Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated typescript to 2.1v. Improved type for combineReducers function. #2700

Closed
wants to merge 1 commit into from
Closed

Conversation

in19farkt
Copy link

Hi everybody. Here is my proposal: let's update Typescript version from 1.8 to 2.1 and use the strength of awesome keyof feature, that let us restrict fields of our redux state.

The current problem is: we can pass almost everything to combineReducers and Typescript will not complain about anything. It will lead to poor user experience and make us to check the correctness of the state ourselves. Although there is a way to tell Typescript how check all fields that we pass to combineReducerskeyof. It is supported only from Typescript 2.1, so I have updated its version, rewrote the typings and updated the tests for compose. The examples below demonstrate the idea quite well:

// We have few fields, let it be just string for example:
type IFirstField = 'first';
type ISecondField = 'second';
type IThirdField = 'third';

// Our redux state contains all those fields:
interface IData {
  first: IFirstField;
  second: ISecondField;
  third: IThirdField;
}

// Current typing should be:
type Reducer<S> = (state: S, action: AnyAction) => S;
interface ReducersMapObject {
  [key: string]: Reducer<any>;
}
type combineReducers = <S>(reducers: ReducersMapObject) => Reducer<S>;

// The problem is shown below
// typescript just swallow error and tell us nothing:
const invalidReducer2 = combineReducers<IData>({
  first: (state: ISecondField, action: AnyAction) => state,  // notice we have used incorrect fields
  second: (state: IFirstField, action: AnyAction) => state,  // here should be ISecondField
});
const invalidReducer1 = combineReducers<IData>({}); // we could even pass nothing!

// Proposed typings with "keyof"
// Now all state fields are bound to exactly fields
type Reducer<S> = (state: S, action: AnyAction) => S;
type ReducersMapObject<S> = {
  [key in keyof S]: Reducer<S[key]>;
}
type combineReducers = <S>(reducers: ReducersMapObject<S>) => Reducer<S>;

// Now Typescript complains about miscorrect types:
const invalidReducer2 = combineReducers<IData>({
  first: (state: ISecondField, action: AnyAction) => state,  // notice, here is ISecondField
  second: (state: IFirstField, action: AnyAction) => state,
  third: (state: IThirdField, action: AnyAction) => state,  
});  // Yeah, we'll see error here
const invalidReducer1 = combineReducers<IData>({});  //  Eventually Typescript will cry!

// But with correct fields Typescript is happy :)
const validReducer = combineReducers<IData>({
  first: (state: IFirstField, action: AnyAction) => state,
  second: (state: ISecondField, action: AnyAction) => state,
  third: (state: IThirdField, action: AnyAction) => state,
});

Hope it will be usefull pull request for community and looking forward for your feedback. Thank you!

@in19farkt
Copy link
Author

Ah. Just seen 8033325 and #2563 - please ignore!

@in19farkt in19farkt closed this Nov 7, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant