How can I omit interface by union type recursively in typescript?

92 Views Asked by At

I'd like to omit recursively by type that includes in union types, and remove some union types

Here's the example.

Normal and Admin must be union types

interface Admin {
    admin: never;
}

interface Normal {
    normal: never;
}


interface A {
    a: number;
    b: Admin | number;
    c: Normal | string;
    d?: number | string | null;
    e: {
        f: Admin | string;
        g: number;
    };
    h: {
        i: {
            j: Admin | number;
            k: string;
        };
    };
    l: Normal | boolean;
}


type OmitNormal = OmitRecursiveByType<A, Admin>; 

And I want the result like this.

{
    a: number;
    c: string;
    d?: number | string | null;
    e: {
        g: number;
    };
    h: {
        i: {
            k: string;
        };
    };
    l: boolean;
}

In this case, key that has Admin union type is removed. However key that has Normal isn't removed.

Here is another example

interface A {
    a: number;
    b: Admin | number;
    c: Normal | string;
    d: null|number
}

type OmitAll = OmitRecursiveByType<A, Admin|Normal>;

result

{
   a: number;
   d: number|null;
}

Here's the other example

interface A {
    a: number;
    b: string;
    c: number|string;
    d: number|null;
    e: {
       f: string;
       g: number|null;
    }
}
type NotStringA = OmitRecursiveByType<A, string>

result

{
    a: number;
    d: number|null;
    e: {
       g: number|null;
    }
}

How can I make OmitRecursiveByType<T, P>?

1

There are 1 best solutions below

0
Joel On

Based on your description and examples it sounds like you need the following:

  • If the value type of a property overlaps with P, the property is removed.
  • If the value of a property is an object, the step above is applied recursively.
  • At the end, all occurences of Admin and Normal are removed.

If this sums up your problem, it should be solved by the following type:

type OmitRecursiveByType<T extends Object, P> = {
    [K in keyof T]: T[K] extends object
    ? OmitRecursiveByType<T[K], P> 
    : Extract<T[K], P> extends never
      ? Exclude<T[K], Admin | Normal>
      : never
}