简体   繁体   中英

how to define type for a constant using typescript?

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;
    }

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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM