Home > OS >  TypeScript: Extract then Omit from union
TypeScript: Extract then Omit from union

Time:05-07

Let's say I have a Vehicle union type that looks like that:

interface Car {
  color: string;
  doors: number;
  wheels: number;
}

interface Plane {
  color: string;
  wings: number;
}

type Vehicle = Car | Plane;

I want (1) to extract from this union the types that extend a given type argument (this can easily be achieved using the Extract utility type) and (2) to omit from the extracted type(s) the keys of that same type argument. Here's the desired output:

type Result1 = ExtractOmit<{ wheels: number; }>;
// This should give me the result of Omit<Car, "wheels">:
// { color: string; doors: number; }

type Result2 = ExtractOmit<{ wings: number; }>;
// This should give me the result of Omit<Plane, "wings">:
// { color: string; }

type Result3 = ExtractOmit<{ foo: number; }>;
// This should produce an error since foo is neither in Car nor Plane

Here's an unsuccessful attempt:

type ExtractOmit<T> = Omit<Extract<Vehicle, T>, keyof T>;
// T extends what?

The right part seems right to me but I can't figure out how to put up the left one.

Any suggestion?

TypeScript playground

CodePudding user response:

interface Car {
    color: string;
    doors: number;
    wheels: number;
}

interface Plane {
    color: string;
    wings: number;
}

type Vehicle = Car | Plane;

type OmitExtract<T extends Partial<Vehicle>> = Omit<Extract<Vehicle, T>, keyof T>;

type Result = OmitExtract<{ wheels: number; }>;

type Result1 = OmitExtract<{ wheels: number; }>;
// This should give me the result of Omit<Car, "wheels">:
// { color: string; doors: number; }

type Result2 = OmitExtract<{ wings: number; }>;
// This should give me the result of Omit<Plane, "wings">:
// { color: string; }

The above seems to work as expected.

The key pieces here being using "Vehicle" (I noticed you used Element earlier) and having T extend the Partial on the left to give it the supertype necessary for Extract to know what to extract from correctly.

Edit: playground link

  • Related