1

How to refer constants in types? For example, I have below constant values such as A and B and need to create an Action Type so I can use Action type in switch case later

const PATH = '@@test/';
export const A = `${PATH}A`;
export const B = `${PATH}B`;

export type Action =
// UI actions
{ type: typeof A, payload: { a: any } }
| { type:  B, payload: { b: boolean }}

// usage

const id = (state= initialState, action: Action) => {
    const nextState = state;
    switch (action.type) {
        case A: {
          const{a} = action.payload;
            break;
        }
        case B: {
          const { b} = action.payload;
         break;
        }
        default: 
          break;
    }

1 Answer 1

1

TypeScript currently (as of v2.5) lacks the ability to concatenate string literal types. When you concatenate two string literals in TypeScript, the resulting type is only known to be string. For example, it has no idea that the following is correct:

const x = "x";
const xx: "xx" = x + x; // error!

In your case, TypeScript infers A and B to be string values:

export const A = `${PATH}A`; // inferred as string
export const B = `${PATH}B`; // inferred as string

And therefore, an Action is not considered to be a discriminated union since the type property is the same in both cases:

export type Action =
  { type: typeof A, payload: { a: any } } | 
  { type: typeof B, payload: { b: boolean } }

The only way around this for you to manually specify the literal types for A and B, possibly with a runtime check to make sure that you haven't misconfigured the constants. Yes, that's unfortunate, but it works:

const PATH = '@@test/';
export const A = "@@test/A";
export const B = "@@test/B";
if (!A.startsWith(PATH) || !B.startsWith(PATH)) {
  throw new Error("Bad configuration");
}

Now, Action is a proper discriminated union and when you switch on the type property, TypeScript will narrow types for you automatically:

declare const action: Action;
switch (action.type) {
  case A: {
    const { a } = action.payload; // okay
    break;
  }
  case B: {
    const { b } = action.payload; // okay
    break;
  }
  default:
    const assertNever: never = action; // okay
    break;
}

Hope that helps; good luck!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.