Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript: Omit a property from all interfaces in a union, but keep the union structure

Tags:

typescript

I'm new to typescript and I have a few interfaces defined like so:

interface A {
  toRemove: string;
  key1: "this1";
  key2: number;
}
interface B {
  toRemove: string;
  key1: "this2";
  key3: string;
}

And a union of both interfaces:

type C = A|B;

What I want to do is to remove the toRemove key from both interfaces through C, something like this:

type CC = Omit<A, "toRemove">|Omit<B, "toRemove">;

But without having to omit the key from both interfaces. This would be ideal:

type CC = Omit<C, "toRemove">;

But, unfortunately, CC will be of type Pick<A|B, "key1">, where key1 is the key present in both interfaces.

In essence, what I'm trying to achieve is a type of "function" to transform:

A1|A2|...|An

into:

Omit<A1, K keyof A1>|Omit<A1, K keyof A2>|...|Omit<An, K keyof An>

I came across this answer https://stackoverflow.com/a/56297816/6520174 and I have a feeling that part of what I need is somewhere in there, but I don't really understand what's going on in that code.

like image 486
Luis Pais Avatar asked Jul 18 '19 23:07

Luis Pais


People also ask

How do you omit a property in TypeScript?

Use the Omit utility type to exclude a property from a type, e.g. type WithoutCountry = Omit<Person, 'country'> . The Omit utility type constructs a new type by removing the specified keys from the existing type. Copied!

What is discriminated union TypeScript?

A discriminated type union is where you use code flow analysis to reduce a set of potential objects down to one specific object. This pattern works really well for sets of similar objects with a different string or number constant for example: a list of named events, or versioned sets of objects.

How do you handle a union type in TypeScript?

TypeScript Union Type Narrowing To narrow a variable to a specific type, implement a type guard. Use the typeof operator with the variable name and compare it with the type you expect for the variable.

How does omit work in TypeScript?

The TypeScript Omit utility type Like the Pick type, the Omit can be used to modify an existing interface or type. However, this one works the other way around. It will remove the fields you defined. We want to remove the id field from our user object when we want to create a user.


1 Answers

You want to distribute the Omit across a union. Luckily, you can use distributive conditional types to achieve this:

type DistributiveOmit<T, K extends keyof any> = T extends any
  ? Omit<T, K>
  : never;

The T extends any construction looks like it doesn't do much, but since T is a type parameter, it distributes the conditional type across any union constituents of T.

Let's test it:

type CC = DistributiveOmit<C, "toRemove">;
// type CC = Pick<A, "key1" | "key2"> | Pick<B, "key1" | "key3">

You can verify that this is equivalent to the CC type you want.

Hope that helps; good luck!

Link to code

like image 172
jcalz Avatar answered Oct 05 '22 02:10

jcalz