'How to omit an union type depending on field value

I have this type (come from third party library):

type StackActionType = {
    type: 'REPLACE';
    payload: {
        name: string;
        key?: string | undefined;
        params?: object;
    };
    source?: string;
    target?: string;
} | {
    type: 'PUSH';
    payload: {
        name: string;
        params?: object;
    };
    source?: string;
    target?: string;
} | {
    type: 'POP';
    payload: {
        count: number;
    };
    source?: string;
    target?: string;
} | {
    type: 'POP_TO_TOP';
    source?: string;
    target?: string;
};

I would like to infer remaining union types. I can achieve that with field key/name. ex:

const action: StackActionType = ...;
if("payload" in action) {
  // action is infered with union types of: 'REPLACE', 'PUSH', 'POP' (contains "payload" field) and 'POP_TO_TOP' is omited 
}

But there is a way to achieve that using field value instead of field name, ex:

if(["PUSH", "REPLACE"].includes(action.type)) {
 // action should only infer union of 'REPLACE' & 'PUSH'. But this is not working...
} 

Any idea (without copying/alter original type) ?

EDIT:

Here is a try with type guard & if: Typscript sandbox



Solution 1:[1]

I believe your solution will work if you instead use:

if (action.type == 'PUSH' || action.type == 'REPLACE') {}

Typescript cannot statically analyze the type possibilities when you use [].includes since an array can technically contain dynamic (runtime) values.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Josh Bothun