{"action":"created","issue":{"url":"https://api.github.com/repos/piotrwitek/typesafe-actions/issues/22","repository_url":"https://api.github.com/repos/piotrwitek/typesafe-actions","labels_url":"https://api.github.com/repos/piotrwitek/typesafe-actions/issues/22/labels{/name}","comments_url":"https://api.github.com/repos/piotrwitek/typesafe-actions/issues/22/comments","events_url":"https://api.github.com/repos/piotrwitek/typesafe-actions/issues/22/events","html_url":"https://github.com/piotrwitek/typesafe-actions/issues/22","id":308510253,"number":22,"title":"New API - v1.2","user":{"login":"piotrwitek","id":739075,"avatar_url":"https://avatars0.githubusercontent.com/u/739075?v=4","gravatar_id":"","url":"https://api.github.com/users/piotrwitek","html_url":"https://github.com/piotrwitek","followers_url":"https://api.github.com/users/piotrwitek/followers","following_url":"https://api.github.com/users/piotrwitek/following{/other_user}","gists_url":"https://api.github.com/users/piotrwitek/gists{/gist_id}","starred_url":"https://api.github.com/users/piotrwitek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/piotrwitek/subscriptions","organizations_url":"https://api.github.com/users/piotrwitek/orgs","repos_url":"https://api.github.com/users/piotrwitek/repos","events_url":"https://api.github.com/users/piotrwitek/events{/privacy}","received_events_url":"https://api.github.com/users/piotrwitek/received_events","type":"User","site_admin":false},"labels":[{"id":789857590,"url":"https://api.github.com/repos/piotrwitek/typesafe-actions/labels/feature","name":"feature","color":"6dce12","default":false}],"state":"open","locked":false,"assignee":{"login":"piotrwitek","id":739075,"avatar_url":"https://avatars0.githubusercontent.com/u/739075?v=4","gravatar_id":"","url":"https://api.github.com/users/piotrwitek","html_url":"https://github.com/piotrwitek","followers_url":"https://api.github.com/users/piotrwitek/followers","following_url":"https://api.github.com/users/piotrwitek/following{/other_user}","gists_url":"https://api.github.com/users/piotrwitek/gists{/gist_id}","starred_url":"https://api.github.com/users/piotrwitek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/piotrwitek/subscriptions","organizations_url":"https://api.github.com/users/piotrwitek/orgs","repos_url":"https://api.github.com/users/piotrwitek/repos","events_url":"https://api.github.com/users/piotrwitek/events{/privacy}","received_events_url":"https://api.github.com/users/piotrwitek/received_events","type":"User","site_admin":false},"assignees":[{"login":"piotrwitek","id":739075,"avatar_url":"https://avatars0.githubusercontent.com/u/739075?v=4","gravatar_id":"","url":"https://api.github.com/users/piotrwitek","html_url":"https://github.com/piotrwitek","followers_url":"https://api.github.com/users/piotrwitek/followers","following_url":"https://api.github.com/users/piotrwitek/following{/other_user}","gists_url":"https://api.github.com/users/piotrwitek/gists{/gist_id}","starred_url":"https://api.github.com/users/piotrwitek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/piotrwitek/subscriptions","organizations_url":"https://api.github.com/users/piotrwitek/orgs","repos_url":"https://api.github.com/users/piotrwitek/repos","events_url":"https://api.github.com/users/piotrwitek/events{/privacy}","received_events_url":"https://api.github.com/users/piotrwitek/received_events","type":"User","site_admin":false}],"milestone":{"url":"https://api.github.com/repos/piotrwitek/typesafe-actions/milestones/4","html_url":"https://github.com/piotrwitek/typesafe-actions/milestone/4","labels_url":"https://api.github.com/repos/piotrwitek/typesafe-actions/milestones/4/labels","id":3216405,"number":4,"title":"v1.2.0","description":null,"creator":{"login":"piotrwitek","id":739075,"avatar_url":"https://avatars0.githubusercontent.com/u/739075?v=4","gravatar_id":"","url":"https://api.github.com/users/piotrwitek","html_url":"https://github.com/piotrwitek","followers_url":"https://api.github.com/users/piotrwitek/followers","following_url":"https://api.github.com/users/piotrwitek/following{/other_user}","gists_url":"https://api.github.com/users/piotrwitek/gists{/gist_id}","starred_url":"https://api.github.com/users/piotrwitek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/piotrwitek/subscriptions","organizations_url":"https://api.github.com/users/piotrwitek/orgs","repos_url":"https://api.github.com/users/piotrwitek/repos","events_url":"https://api.github.com/users/piotrwitek/events{/privacy}","received_events_url":"https://api.github.com/users/piotrwitek/received_events","type":"User","site_admin":false},"open_issues":1,"closed_issues":0,"state":"open","created_at":"2018-03-26T08:47:47Z","updated_at":"2018-03-26T10:10:59Z","due_on":null,"closed_at":null},"comments":12,"created_at":"2018-03-26T10:10:59Z","updated_at":"2018-03-27T22:13:58Z","closed_at":null,"author_association":"OWNER","body":"## Road to v1.2: New API\r\n\r\nI'm working on New API using the new language feature ([conditional types](https://github.com/Microsoft/TypeScript/pull/21847)) coming to TypesScript in the next release (v2.8)\r\n\r\n**I have already published working version that is compatible with recent typescript@rc release**\r\n> to install `yarn add typescript@rc typesafe-actions@1.2.0-rc.0`\r\n\r\nSome changes are inspired by the suggestion from the past and I would really appreciate some feedback from their authors:\r\n- #18 @CzBuCHi\r\n- #17 @Jack-Works\r\n- #12 @flq\r\n- #21 @duro\r\n- #19 @farzadmf @dziamid\r\n\r\nThe implementation of a new API is taking place on the [next](https://github.com/piotrwitek/typesafe-actions/tree/next) branch, and will be released on the release of TypeScript v2.8.\r\n\r\n> all of the examples are working and have test's against them so they should be rock solid \r\n\r\n### Finished\r\n\r\n#### `ActionsUnion`\r\n> conditional mapped type, will provide much cleaner and experience to get Union Type of actions\r\n```ts\r\nimport { ActionsUnion } from 'typesafe-actions';\r\nimport * as actions from './todos-duck-module';\r\n\r\ntype RootAction = ActionsUnion<typeof actions>;\r\n```\r\n \r\n#### `ReturnType`\r\n> getting type declaration of action will now be possible to derive from action creator on call site without the need to declare tons of boilerplate before-hand:\r\n```ts\r\nimport { ReturnType, createAction } from 'typesafe-actions';\r\n\r\nconst increment = createAction('INCREMENT');\r\n\r\nfunction incrementReducer(state: State, action: ReturnType<typeof increment>) {\r\n...\r\n```\r\n\r\n#### `buildAction`\r\n`import { buildAction } from 'typesafe-actions'`\r\n> function will accept action type and return an object with multiple methods to create different action creators described below:\r\n\r\n- `buildAction('INCREMENT').empty()`\r\n```ts\r\nconst increment = buildAction('INCREMENT').empty();\r\nexpect(increment()).toEqual({ type: 'INCREMENT' }); //  { type: 'INCREMENT' }\r\nexpect(getType(increment)).toBe('INCREMENT'); // 'INCREMENT'\r\n```\r\n\r\n- `buildAction('INCREMENT').payload<P>()`\r\n```ts\r\nconst add = buildAction('ADD').payload<number>();\r\nexpect(add(10)).toEqual({ type: 'ADD', payload: 10 }); // { type: 'ADD'; payload: number }\r\nexpect(getType(add)).toBe('ADD'); // 'ADD'\r\n```\r\n\r\n- `buildAction('INCREMENT').async<R, S, F>()`\r\n```ts\r\ntype User = { name: string };\r\nconst fetchUsers = buildAction('LIST_USERS').async<void, User[], string>();\r\nexpect(fetchUsers.request())\r\n    .toEqual({ type: 'LIST_USERS_REQUEST' }); // { type: 'LIST_USERS' & 'REQUEST' }\r\nexpect(fetchUsers.success([{ name: 'Piotr' }]))\r\n    .toEqual({ type: 'LIST_USERS_SUCCESS', payload: [{ name: 'Piotr' }] }); // { type: 'LIST_USERS' & 'SUCCESS'; payload: User[] }\r\nexpect(fetchUsers.failure('error message'))\r\n    .toEqual({ type: 'LIST_USERS_FAILURE', payload: 'error message' }); // { type: 'LIST_USERS' & 'FAILURE'; payload: string }\r\nexpect(getType(fetchUsers.request)).toBe('LIST_USERS_REQUEST'); // 'LIST_USERS' & 'REQUEST'\r\nexpect(getType(fetchUsers.success)).toBe('LIST_USERS_SUCCESS'); // 'LIST_USERS' & 'SUCCESS'\r\nexpect(getType(fetchUsers.failure)).toBe('LIST_USERS_FAILURE'); // 'LIST_USERS' & 'FAILURE'\r\n```\r\n\r\n- `buildAction('NOTIFY').fsa<P>(payloadCreator, metaCreator)`\r\n> API compatible with `redux-actions`\r\n```ts\r\nconst notify = buildAction('NOTIFY').fsa<{ username: string; message?: string }>(\r\n    ({ username, message }) => `${username}: ${message || ''}`,\r\n    ({ username, message }) => ({ username, message })\r\n); // { type: 'NOTIFY'; payload: string; meta: { username: string; message?: string }; }\r\n...\r\n```\r\n\r\n### WIP (optimizing type inference and implementation)\r\n- `createSymbolAction` will give you a new API to use Symbols instead of strings for action type, and still benefit from discriminated union types with complete type safety\r\n```ts\r\nimport { createSymbolAction } from 'typesafe-actions';\r\nimport { RootAction } from './types';\r\n\r\nconst INCREMENT = Symbol(1);\r\nconst ADD = Symbol(2);\r\n\r\nexport default (state = 0, action: RootAction) => {\r\n  switch (action.type) {\r\n    case INCREMENT: {\r\n      return state + 1;\r\n    }\r\n    case ADD: {\r\n      return state + action.payload;\r\n    }\r\n  }\r\n};\r\n\r\n// NB: mandatory to fill in generic symbol type arg, because symbol loses uniqueness when inferred (possibly a bug in typescript@rc)\r\nexport const increment = createSymbolAction<typeof INCREMENT>(INCREMENT);\r\nexport const add = createSymbolAction<typeof ADD, number>(ADD);\r\n```\r\n\r\n### Breaking changes\r\n🎉NO BREAKING CHANGES  🎉\r\n\r\n### Migration to 1.2.0\r\n\r\nHere is an migration example of example in the docs:\r\n- simple payload action\r\n```ts\r\n// current v1.0\r\nconst add = createAction('ADD',\r\n  (amount: number) => ({ type: 'ADD', payload: amount }),\r\n);\r\n\r\n// migration to v1.2 (complete type-safety is still preserved)\r\nconst add = buildAction('ADD').payload<number>;\r\n```\r\n\r\n- advanced Flux Standard Action\r\n```ts\r\n// current v1.0\r\nconst notify = createAction('NOTIFY',\r\n  (username: string, message?: string) => ({\r\n    type: 'NOTIFY',\r\n    payload: `${username}: ${message || ''}`,\r\n    meta: { username, message },\r\n  }),\r\n);\r\n// migration to v1.2 (complete type-safety is still preserved)\r\nconst notify = buildAction('NOTIFY').fsa<{ username: string; message?: string }>(\r\n    ({ username, message }) => `${username}: ${message || ''}`,\r\n    ({ username, message }) => ({ username, message })\r\n);\r\n\r\n```"},"comment":{"url":"https://api.github.com/repos/piotrwitek/typesafe-actions/issues/comments/376693385","html_url":"https://github.com/piotrwitek/typesafe-actions/issues/22#issuecomment-376693385","issue_url":"https://api.github.com/repos/piotrwitek/typesafe-actions/issues/22","id":376693385,"user":{"login":"piotrwitek","id":739075,"avatar_url":"https://avatars0.githubusercontent.com/u/739075?v=4","gravatar_id":"","url":"https://api.github.com/users/piotrwitek","html_url":"https://github.com/piotrwitek","followers_url":"https://api.github.com/users/piotrwitek/followers","following_url":"https://api.github.com/users/piotrwitek/following{/other_user}","gists_url":"https://api.github.com/users/piotrwitek/gists{/gist_id}","starred_url":"https://api.github.com/users/piotrwitek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/piotrwitek/subscriptions","organizations_url":"https://api.github.com/users/piotrwitek/orgs","repos_url":"https://api.github.com/users/piotrwitek/repos","events_url":"https://api.github.com/users/piotrwitek/events{/privacy}","received_events_url":"https://api.github.com/users/piotrwitek/received_events","type":"User","site_admin":false},"created_at":"2018-03-27T22:13:58Z","updated_at":"2018-03-27T22:13:58Z","author_association":"OWNER","body":"@duro Ok got it working :)\r\n```ts\r\nconst actions = {\r\n      empty: buildAction('INCREMENT').empty(),\r\n      payload: buildAction('ADD').payload<number>(),\r\n      fsa: buildAction('SHOW_NOTIFICATION').fsa((message: string) => message),\r\n      async: buildAction('GET_USER').async<number, { name: string }, string>(),\r\n    };\r\n    type RootAction = ActionsUnion<typeof actions>;\r\n// { type: \"INCREMENT\"; } | { type: \"ADD\"; payload: number; } | { type: \"SHOW_NOTIFICATION\"; payload: string; } | { type: \"GET_USER\" & \"REQUEST\"; payload: number; } | { type: \"GET_USER\" & \"SUCCESS\"; payload: { name: string; }; } | { type: \"GET_USER\" & \"FAILURE\"; payload: string; }\r\n```\r\n"}}
{"actor":{"display_login":"piotrwitek"}}