Search code examples
typescripttypescript-typingstypescript-generics

Generic type that removes fields of a certain type from an object


here is what I want to do: Suppose I have an object like this:

interface X {
  a: number;
  b: number;
  с: string;
  d: number[];
}

And I want to delete ALL fields of certain type:

type  DeleteFields <X, number> = ... = {c: string, d:number[]}

The best I've got is like that:

type DeleteFields <T , D> = {
  [P in keyof T]: T[P] extends D ? "" : T[P];
}

type XNumbersNoNum = DeleteFields <X, number>; // { a: ""; b: ""; с: string; d: number[]; }

How can I achieve that behaviour? I tried to play with Omit and etc but didn't get anything better


Solution

  • We will need to use mapped types as you already do, however, we will need to use key remapping to remove the unwanted properties. key remapping is a really useful feature that allows not only removing properties but also modifying the keys based on condition:

    type Getters<Type> = {
        [Property in keyof Type as `get${Capitalize<string & Property>}`]: () => Type[Property]
    };
     
    interface Person {
        name: string;
        age: number;
        location: string;
    }
     
    // type LazyPerson = {
    //    getName: () => string;
    //    getAge: () => number;
    //    getLocation: () => string;
    // }
    type LazyPerson = Getters<Person>;
    

    To remove the properties we will check whether the type of the property extends the type that we want to omit. If the condition is true we will use never as a key, otherwise the key itself without modifying it. By changing the key to never we actually remove the property, since never is empty set, which can't be used as a key:

    type DeleteFields<T, U> = {
      [K in keyof T as T[K] extends U ? never : K]: T[K];
    };
    

    Testing:

    type DeleteFields<T, U> = {
      [K in keyof T as T[K] extends U ? never : K]: T[K];
    };
    
    // type Result = {
    //   с: string;
    //   d: number[];
    // }
    type Result = DeleteFields<X, number>
    

    playground