Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to write filter over union type in typescript

Tags:

typescript

I have the following example to illustrate what I'm trying to get.

const v1: { type: "S"; payload: string } = { type: "S", payload: "test" };
const v2: { type: "N"; payload: number } = { type: "N", payload: 123 };

type Actions = typeof v1 | typeof v2;

const findByType = <A extends Actions>(type: A["type"]) => (
    action: Actions
): action is A => action.type === type;

const filterWithBothNameAndType = [v1, v2].filter(findByType<typeof v1>("S"));
console.log(filterWithBothNameAndType[0].payload.trim());

const findByTypeDoesntWork = <A extends Actions, T extends A["type"]>(type: T) => (
    action: Actions
): action is A => action.type === type;

const filterWithJustType = [v1, v2].filter(findByTypeDoesntWork("S"));
console.log(filterWithJustType[0].payload.trim());

typescript playground

I have function findByType that has right type information and I have function filterWithJustType that has api that I like, but it loses type information. I want api to be just filter("S") without passing generic type. So far it looks like it will only work with classes and instaceof but I wanted to make it work with plain objects.

like image 519
JLarky Avatar asked Nov 09 '17 01:11

JLarky


1 Answers

You can use Exclude or Extract as mentioned by the docs, for example:

type T00 = Exclude<"a" | "b" | "c" | "d", "a" | "c" | "f">;  // "b" | "d"
type T01 = Extract<"a" | "b" | "c" | "d", "a" | "c" | "f">;  // "a" | "c"

type T02 = Exclude<string | number | (() => void), Function>;  // string | number
type T03 = Extract<string | number | (() => void), Function>;  // () => void

like image 87
Mateja Petrovic Avatar answered Oct 25 '22 10:10

Mateja Petrovic