String Literal Types with variables in Typescript

You can use the typeof operator, it returns the inferred type:

export const LOAD_USERS = 'LOAD_USERS';
export const CREATE_USER = 'CREATE_USER';
export interface ACTION {
  type: typeof LOAD_USERS | typeof CREATE_USER,
  payload: any
}

If you want to ensure that the string in your variables will be the action type, then you should use a type alias and explicitly type the variables with that type:

export type ActionNames = 'LOAD_USERS' | 'CREATE_USER';
export const LOAD_USERS: ActionNames = 'LOAD_USERS';
export const CREATE_USER: ActionNames = 'CREATE_USER';

export interface ACTION {
  type: ActionNames;
  payload: any;
}

If the strings in the variables don't match one of the strings in ActionTypes, then you'll get an error, which is desired to prevent mistakes. For example, this would error:

export type ActionNames = 'LOAD_USERS' | 'CREATE_USER';
export const LOAD_USERS: ActionNames = 'LOAD_USERS_TYPO'; // error, good

Update

Note that in newer versions of TypeScript the following is another option:

const actionNames = ['LOAD_USERS', 'CREATE_USER'] as const;
type ActionNames = typeof actionNames[number]; // typed as 'LOAD_USERS' | 'CREATE_USER'

Also, looking back on this question, you probably want to declare your actions with a common string literal type property that's differentiated by the string literal type (see discriminated unions).

For example:

interface LoadUsersAction {
    type: "LOAD_USERS";
}

interface CreateUserAction {
    type: "CREATE_USER";
    name: string;
    // etc...
}

type Actions = LoadUsersAction | CreateUserAction;

Also, I recommend not bothering with the variables. Using the strings directly is type safe.

Tags:

Typescript