{"action":"created","issue":{"url":"https://api.github.com/repos/rackt/redux/issues/290","labels_url":"https://api.github.com/repos/rackt/redux/issues/290/labels{/name}","comments_url":"https://api.github.com/repos/rackt/redux/issues/290/comments","events_url":"https://api.github.com/repos/rackt/redux/issues/290/events","html_url":"https://github.com/rackt/redux/issues/290","id":95943173,"number":290,"title":"Explore using Flow for statically analyzing state and actions","user":{"login":"gaearon","id":810438,"avatar_url":"https://avatars.githubusercontent.com/u/810438?v=3","gravatar_id":"","url":"https://api.github.com/users/gaearon","html_url":"https://github.com/gaearon","followers_url":"https://api.github.com/users/gaearon/followers","following_url":"https://api.github.com/users/gaearon/following{/other_user}","gists_url":"https://api.github.com/users/gaearon/gists{/gist_id}","starred_url":"https://api.github.com/users/gaearon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gaearon/subscriptions","organizations_url":"https://api.github.com/users/gaearon/orgs","repos_url":"https://api.github.com/users/gaearon/repos","events_url":"https://api.github.com/users/gaearon/events{/privacy}","received_events_url":"https://api.github.com/users/gaearon/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/rackt/redux/labels/enhancement","name":"enhancement","color":"84b6eb"},{"url":"https://api.github.com/repos/rackt/redux/labels/help%20wanted","name":"help wanted","color":"159818"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":15,"created_at":"2015-07-19T19:46:56Z","updated_at":"2015-09-25T13:19:19Z","closed_at":null,"body":"See the example from [this PR to Facebook's Flux](https://github.com/facebook/flux/pull/243):\r\n\r\n```js\r\ntype Action =\r\n  {\r\n    type: 'foo',\r\n    foo: number,\r\n  } |\r\n  {\r\n    type: 'bar',\r\n    bar: string,\r\n  };\r\n\r\nvar FooDispatcher: Dispatcher<Action> = new Dispatcher();\r\n\r\nfunction acceptsNumber(x: number): void {}\r\n\r\nFooDispatcher.register(function(action: Action) {\r\n  switch (action.type) {\r\n    case 'foo':\r\n      acceptsNumber(action.foo);\r\n      acceptsNumber(action.bar); // flow error, property not found in object\r\n      break;\r\n\r\n    case 'bar':\r\n      acceptsNumber(action.bar); // flow error, string incompatible with number\r\n      break;\r\n  }\r\n});\r\n\r\ntype NotAction = string;\r\nFooDispatcher.register(function(action: NotAction) {}); // flow error\r\n\r\n// flow error\r\nFooDispatcher.dispatch({\r\n  type: 'foo-typo',\r\n  foo: 100,\r\n});\r\n```\r\n\r\nNow that #254 is merged (into 1.0 branch), I encourage you to help me figure out how to have the same awesomeness in Redux. We probably need to make `createStore` definition generic so that you can say `createStore<MyState, MyAction>(reducer, initialState)` and have your whole reducer tree type checked.\r\n\r\nI'm a Flow noob so any help is welcome. You can start by copying the Counter example, annotating it with Flow and trying to make it type check like in https://github.com/facebook/flux/pull/243."},"comment":{"url":"https://api.github.com/repos/rackt/redux/issues/comments/143218890","html_url":"https://github.com/rackt/redux/issues/290#issuecomment-143218890","issue_url":"https://api.github.com/repos/rackt/redux/issues/290","id":143218890,"user":{"login":"leoasis","id":328001,"avatar_url":"https://avatars.githubusercontent.com/u/328001?v=3","gravatar_id":"","url":"https://api.github.com/users/leoasis","html_url":"https://github.com/leoasis","followers_url":"https://api.github.com/users/leoasis/followers","following_url":"https://api.github.com/users/leoasis/following{/other_user}","gists_url":"https://api.github.com/users/leoasis/gists{/gist_id}","starred_url":"https://api.github.com/users/leoasis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/leoasis/subscriptions","organizations_url":"https://api.github.com/users/leoasis/orgs","repos_url":"https://api.github.com/users/leoasis/repos","events_url":"https://api.github.com/users/leoasis/events{/privacy}","received_events_url":"https://api.github.com/users/leoasis/received_events","type":"User","site_admin":false},"created_at":"2015-09-25T13:19:19Z","updated_at":"2015-09-25T13:19:19Z","body":"The thing is that with this way you will never have the complete safety that you are doing what you want. In your first examples, you don't define the correct types for the reducers that you accept, and you don't specify the correct type of the state of the resulting reducer.\r\nThe solution with tuples, while it may work, will need to define a lot of combineN functions, since in most big enough apps you have a lot of reducers.\r\n\r\nI'm ultimately leaning towards just manually creating the reducer, since `combineReducers` does mostly type and shape checking (both things will also be checked by Flow), and it just add a little convenience shortcut, but, it's not that bad either. Consider the plain solution without `combineReducers`:\r\n\r\n```js\r\ntype AppState = {\r\n  foo: FooState,\r\n  bar: BarState\r\n}\r\n\r\nfunction reducer(state?: AppState, action: Action) : AppState {\r\n  return {\r\n    foo: fooReducer(state && state.foo, action),\r\n    bar: barReducer(state && state.bar, action)\r\n  }\r\n}\r\n```\r\n\r\nIt's not that bad in my optinion, and it has complete type check, since we are defining the reducers signatures.\r\n\r\nWhat do you think? Perhaps it's worth exploring this by adding a new example that would be one of the existing ones but ported to flow without using `combineReducers`"}}