Skip to content

Instantly share code, notes, and snippets.

@vezaynk
Created May 26, 2022 17:50
Show Gist options
  • Save vezaynk/3cdfbcd766c33fd417c37da5a4733184 to your computer and use it in GitHub Desktop.
Save vezaynk/3cdfbcd766c33fd417c37da5a4733184 to your computer and use it in GitHub Desktop.
interface SpacingProps {
__typename: string,
property1: {
__typename: string;
a: 2;
nested: {
__typename: string,
x: 3
}
},
property2: {
__typename: string;
b: 3;
},
}
type NestedOmit<T,K extends string>=Omit<{
[key in keyof T]: NestedOmit<Omit<T[key],K>, K>;
}, K>;
const test: NestedOmit<SpacingProps, '__typename'> = {
property1: {
a: 2,
nested: {
x: 3
}
},
property2: {
b: 3
}
};
@vezaynk
Copy link
Author

vezaynk commented May 27, 2022

@vezaynk
Copy link
Author

vezaynk commented May 27, 2022

Covariants were having issues. This fixes them:

type NullUnionOmit<T, K extends string | number | symbol> = null extends T
  ? UnionOmit<NonNullable<T>, K> | null
  : UnionOmit<T, K>;
type UnionOmit<T, K extends string | number | symbol> = T extends unknown ? Omit<T, K> : never;

type NestedOmitHelper<T, K extends string> = {
  [key in keyof T]: NestedOmit<T[key], K>
};
type NestedOmit<T, K extends string> = NonNullable<T> extends {
  [prop in K]: any;
}
  ? NullUnionOmit<NestedOmitHelper<T, K>, K>
  : NestedOmitHelper<T, K> | T; 

@vezaynk
Copy link
Author

vezaynk commented May 27, 2022

NonNullable is unncessary:

type NullUnionOmit<T, K extends string | number | symbol> = null extends T
  ? UnionOmit<NonNullable<T>, K> | null
  : UnionOmit<T, K>;
type UnionOmit<T, K extends string | number | symbol> = T extends unknown ? Omit<T, K> : never;

type NestedOmitHelper<T, K extends string> = {
  [key in keyof T]: NestedOmit<T[key], K>
};
type NestedOmit<T, K extends string> = T extends {
  [prop in K]: any;
}
  ? NullUnionOmit<NestedOmitHelper<T, K>, K>
  : NestedOmitHelper<T, K> | T; 

@vezaynk
Copy link
Author

vezaynk commented May 27, 2022

Final version for realsies:

type UnionOmit<T, K extends string | number | symbol> = T extends unknown
  ? Omit<T, K>
  : never;
type NullUnionOmit<T, K extends string | number | symbol> = null extends T
  ? UnionOmit<NonNullable<T>, K>
  : UnionOmit<T, K>;
type SafeOmit<T, K extends string | number | symbol> = T extends {
  [P in K]: any;
}
  ? NullUnionOmit<T, K>
  : T;
type RecursiveOmit<T, K extends string | number | symbol> = T extends {
  [P in K]: any;
}
  ? SafeOmit<{ [P in keyof T]: RecursiveOmit<T[P], K> }, K>
  : {
      [P in keyof T]: RecursiveOmit<T[P], K>;
    };

const cleanSolarSystem: RecursiveOmit<SolarSystem, "__typename"> = {
  //__typename: "SolarSystem",
  id: 123,
  name: "The Solar System",
  star: {
    //__typename: "Planet",
    id: 123,
    inhabitants: null,
    name: "Sun",
    size: 9999,
  },
  planets: [
    {
      //__typename: "Planet",
      id: 123,
      name: "Earth",
      size: 12345,
      inhabitants: [
        {
          //__typename: "LifeForm",
          id: 123,
          name: "Human",
        },
      ],
    },
  ],
};

Playground

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment