Typescript security type in switch statements

I work with Redux and I try to keep my gearboxes safe. I found sample code from the ngrx-store / example application where they do a great job of this. ( https://github.com/ngrx/example-app/blob/master/src/app/actions/book.ts )

Integrating this into my own project, I noticed something strange that I can’t explain. Check out the following code example (some comments on the line):

// Action has a type and payload property interface Action { type: string; payload?: any; } // Here I declare the action types as plain strings const FIRST = "FIRST"; const SECOND = "SECOND"; // I create classes for every action with there respective types class FirstAction implements Action { public type = FIRST; payload: { id: number }; public constructor(id: number) { this.payload = { id }; } } class SecondAction implements Action { public type = SECOND; public constructor() { } } // Create a union type type Actions = FirstAction | SecondAction; // Use the union type as type parameter in my function function test(action: Actions): void { switch (action.type) { case FIRST: // compiler will complain it cannot find the payload // property on Actions let temp = action.payload.id; case SECOND: // empty default: //empty } } 

If I replace the FIRST and SECOND property definition as follows, this will work.

 export function type<T>(label: T | ''): T { return <T>label; } const FIRST = type("FIRST"); const SECOND = type("SECOND"); 

As far as I can see, a type function only returns a string to a string. Why does the code work with calling the type function, but not when declaring strings immediately?

Here is an example of a typescript playground where you can simply comment on the definitions or exit (first with a working version).

+5
source share
3 answers

This is because the TSC compiler cannot distinguish 2 values:

 const FIRST = "FIRST"; const SECOND = "SECOND"; 

These are both types of string , so TSC does not know what belongs. You must specify its type and what you do by discarding it using the type function.

But it is easier if you write it like this:

 const FIRST: "FIRST" = "FIRST"; const SECOND: "SECOND" = "SECOND"; 

Typescript Playground

+2
source

It works only with a constant, and not with regular expressions, without variables.

 switch(variable_expression) { case constant1: { //code; break; } case constant2: { //code; break; } default: { //code; break; } } 
0
source

I would use the as operator:

 let temp = (action as FirstAction).payload.id; 

Some other thoughts:
- Do you really need Actions , if you already have an Action , what do all your action classes implement?
- Removing each case's gearbox into a function can help in readability and unit testing.
- Remember that gearboxes take state and action, and also return state (I understand you just simplified your example).

 function test(state: State, action: Action): State { switch (action.type) { case FIRST: return handleFirst(state, action as FirstAction); case SECOND: return handleSecond(state, action as SecondAction); default: return state; } } function handleFirst(state: State, action: FirstAction): State { let temp = action.payload.id; // ... } // ... 
-1
source

Source: https://habr.com/ru/post/1259813/


All Articles