Home > Software engineering >  How to filter out all objects from type?
How to filter out all objects from type?

Time:10-12

I have a type, FilteredType, which looks like this:

type ArrayKeys<T> = { [K in keyof T]: T[K] extends Array<any> ? K : never }[keyof T];

interface MyInterface {
    a: number;
    b: string;
    c: string;
    d: string[];
    e: number[];
    f: { // How can I filter out 'object' properties such as this in addition to arrays?
        g: number;
        h: string;
    }
}

type FilteredType = Omit<MyInterface, ArrayKeys<MyInterface>>;

In addition to filtering out arrays, I want to filter out complex object properties such as 'f'. Is that possible?

CodePudding user response:

Arrays are objects, so you can filter using the object type which specifically means "anything not a primitive":

type ObjectKeys<T> = { [K in keyof T]: T[K] extends object ? K : never }[keyof T];
    
type FilteredType = Omit<MyInterface, ObjectKeys<MyInterface>>;
/* type FilteredType = {
    a: number;
    b: string;
    c: string;
} */

(If you are using ESLint's ban-types rule and it complains about object, you should reconfigure it to not complain. There is nothing wrong with using object in this context.)


Note also that if you're using Omit to filter keys based on some type function, you can do it in a single type function via key remapping:

type OmitObjectKeys<T> = { [K in keyof T as T[K] extends object ? never : K]: T[K] }

type FilteredType2 = OmitObjectKeys<MyInterface>
/* type FilteredType2 = {
    a: number;
    b: string;
    c: string;
} */

Playground link to code

CodePudding user response:

If you were to reverse your logic to keep only "primitive" values, it would solve itself. See KeysOfPrimitive you can extend it further to allow only specified types KeysOfSpecified.

type primitives = string | number | symbol | boolean | bigint;
type KeysOfPrimitive<T extends Record<any, any>> = { [K in keyof T]: T[K] extends primitives ? K : never }[keyof T];
type KeysOfSpecified<T extends Record<any, any>, ToKeep> = { [K in keyof T]: T[K] extends ToKeep ? K : never }[keyof T];

interface MyInterface {
    a: number;
    b: string;
    c: string;
    d: string[];
    e: number[];
    f: {
        g: number;
        h: string;
    }
}

type T1 = Pick<MyInterface, KeysOfPrimitive<MyInterface>>;
type T2 = Pick<MyInterface, KeysOfSpecified<MyInterface, string>>;
type T3 = Pick<MyInterface, KeysOfSpecified<MyInterface, number[]>>;

playground

  • Related