I have a union type that can be narrowed based on a kind property. I would like to create a function whose input is one of those kinds ("Foo" or "Bar"), and whose output is a function that accepts the matching type as input (FooType or BarType).
I tried implementing such a function (getHandler) as follows:
type FooType = { kind: "Foo", fooMsg: string }
type BarType = { kind: "Bar", barMsg: string }
function getHandler(kind: "Foo" | "Bar") {
switch (kind) {
case "Foo":
return { handle: (foo: FooType) => console.log(foo.fooMsg) };
case "Bar":
return { handle: (bar: BarType) => console.log(bar.barMsg) };
}
}
const fooBar: FooType | BarType = getFooOrBar(); // return type is 'FooType | BarType'
getHandler(fooBar.kind).handle(fooBar);
But this throws an error on the call to handle(fooBar):
TS2345: Argument of type 'FooType | BarType' is not assignable to parameter of type 'never'.
I understand the error, but I'd like to know if there's a way to communicate to TypeScript that this will not fail (without resorting to using any or //@ts-ignore).
Specifically, because getHandler was called using fooBar's kind, I know that the handle function will be able to operate on fooBar. Is there a way express that fact in TypeScript?