piotrwitek / typesafe-actions

Typesafe utilities for "action-creators" in Redux / Flux Architecture
https://codesandbox.io/s/github/piotrwitek/typesafe-actions/tree/master/codesandbox
MIT License
2.41k stars 98 forks source link

Unable to use an object for defining types with createAction #15

Closed mwq27 closed 6 years ago

mwq27 commented 6 years ago

I was wondering if this is the intended use.

export const actions = {
 login: createAction(types.LOGIN_REQUEST, (email: string, password: string) => ({
    type: types.LOGIN_REQUEST,
    payload: { email, password },
  })),
  loginSuccess: createAction('AUTH/LOGIN_SUCCESS', (authData: any) => ({
    type: 'AUTH/LOGIN_SUCCESS',
    payload: { authData },
  })),
...

With the login action above, I get this output with returnsOfActions:

const returnsOfActions = Object.values(actions).map($call);
type AppAction = typeof returnsOfActions[number];
/**** Here's what the types looks like (hovering my mouse over returnsOfActions **/
const returnsOfActions: ({
    type: string;
    payload: {
        email: string;
        password: string;
    };
} | {
    type: "AUTH/LOGIN_SUCCESS";
    payload: {
        authData: any;
    };

The type for the login_request action returns as string, and not the actual value of types.LOGIN_REQUEST. Is there any way I can continue using my types object, or do I need to use the actual value when I use createAction?

Thanks

sylvanaar commented 6 years ago

Can you show the code for types.LOGIN_REQUEST including it's type definition if you wrote one. You don't have to use a raw string - but what you supply has to have a literal string type - not just a string, and there are a few ways that you could end up widening your literal string type, like creating it with concatenation.

mwq27 commented 6 years ago

Here's my types object:

export const types = {
  AUTO_LOGIN: 'AUTH/AUTH_AUTO_LOGIN',
  SIGNUP_REQUEST: 'AUTH/SIGNUP_REQUEST',
  SIGNUP_SUCCESS: 'AUTH/SIGNUP_SUCCESS',
....

I don't have a typedef for that object.

mwq27 commented 6 years ago

Do i need to do this:

type MyTypes = {
  AUTO_LOGIN: 'AUTH/AUTH_AUTO_LOGIN',
  SIGNUP_REQUEST: 'AUTH/SIGNUP_REQUEST',
....
export const types: MyTypes = {
  AUTO_LOGIN: 'AUTH/AUTH_AUTO_LOGIN',
  SIGNUP_REQUEST: 'AUTH/SIGNUP_REQUEST',
...
sylvanaar commented 6 years ago

Use a string enum. It's complicated but literal types are only used for constant values, and in an object literal the properties are considered mutable. Though your solution works too - just more typing - it does let you use keyof to create union types though. You could have also said foo: "FOO" as "FOO"

mwq27 commented 6 years ago

Thank you, I switched to using an enum. Thanks for your help.