简体   繁体   中英

Typescript pattern matching with subtype of string literal type

export interface Action{
    type: string;
}

    export interface LoadTodos {
      type: "LOAD_TODOS_ACTION"
    }

    export interface AddTodo {
      type: "ADD_TODO_ACTION",
      todo: Todo
    }

export type KnownAction = LoadTodos | LoadTodosSuccess | AddTodo;

function isSomeType<T extends KnownAction>(x: any): x is T {
    return x && typeof (x.type) === "LOAD_TODOS_ACTION";
}


let knownAction: actions.KnownAction = { type: "LOAD_TODOS_ACTION" };


if (isSomeType(knownAction)) {
    let loadTodosAction = knownAction; // load Todos type
}

I'm expecting the behaviour above. I want to do this in a generic way so I don't want to repeat if, else statement in isSomeType function.Basically I want to convert string literal type into appropriate type based on 'type' property. My attempt was to do this:

function isSomeType<T extends Action>(x: any): x is T {
    type p1 = T['type'];
    return x && typeof (x.type) === p1;
}

But the message says: 'p1' only refers to a type but is used as a variable here.

Is there a way to do this?

Surprisingly the answer is: do nothing.

function isSomeType<T extends KnownAction>(x: T):T {
    return x;
}

Basically typescript will interfere type automatically whenever function with the above signature is called.

EDIT:

 let knownAction: actions.KnownAction = { type: "LOAD_TODOS_ACTION" }; // KnownAction type
 let knownAction2 = isSomeType(knownAction) // LoadTodosAction type

Not a definitive answer, but I don't believe you can.

FWIW the recommended approach would probably be a switch on the discriminating member .

As for your code, you may be losing track of where type information is lost. The typeof operator will not be meaningful here. typeof is a runtime operation and even if you write type: "LOAD_TODOS_ACTION" in your code at runtime typeof x.type will return string which I expect is not helpful to you. A string literal type means that the only acceptable assignable value is that string, not that a new type is introduced.

So in order to achieve what you're looking for we'd need to be able to get an interface member's compile time type information. As far as I know, there is no way to do this. When there is one, this is possible, but until then I don't believe it is.

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