Search code examples
typescriptreducersunion-types

Union type for the similar structure of the interfaces


How to implement Union type with enabled typeof flag for variables in typescript config

TS playground is there

The removing of type definition in the first line works fine, but tslint generetes the error for it. Examples in http://www.typescriptlang.org/docs/handbook/advanced-types.html with (entity) did not help.

const TYPE_A: string = 'TYPE_A'; // <- type difinition here breaks line 19
interface Action_A {
    type: typeof TYPE_A;
    payload: {
        entities: [];
    }
}

const TYPE_B = 'TYPE_B';
interface Action_B {
    type: typeof TYPE_B;
    payload: {
        id: number
    }
} 

const shouldBeReducer = (action: Action_A | Action_B) => {
    if (action.type === TYPE_A) {
        return action.payload.entites // <- entities field is not defined
    }
}

type definition in the reducer should work correct, but exeption is displayed


Solution

  • Use class instead of interface and instanceof type guard.

    const TYPEA: number = 1; // type difinition here breaks line 19
    class ActionA {
        type: typeof TYPEA;
        payload: {
            entities: [];
        }
    }
    
    const TYPEB = 2;
    class ActionB {
        type: typeof TYPEB;
        payload: {
            id: number
        }
    } 
    
    const reducer = (action: ActionA | ActionB) => {
        if (action instanceof ActionB) {
            action.payload.id // OK
        }
    }
    

    Playground

    However if you want to keep interfaces, you should change your code to this:

    const TYPEA = 1 as 1; // type difinition here breaks line 19
    interface ActionA {
        type: 1;
        payload: {
            entities: [];
        }
    }
    
    const TYPEB = 2 as 2;
    interface ActionB {
        type: typeof TYPEB;
        payload: {
            id: number
        }
    } 
    
    const reducer = (action: ActionA | ActionB) => {
        if (action.type === TYPEB) {
            action.payload.id // OK
        }
    }
    

    Playground

    The problem was that TYPEA and TYPEB was inferred as number and not number literals (1, 2).