Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Return union of keys from a object with given type

I’m trying to extract a union of the keys of a certain type within an object.

With my best effort, I only made it this far.

export type KeysOfType<T, U> = { [k in keyof T]: T[k] extends U ? k : never }[keyof T];

With that code, given Config and passing boolean as the second argument, it returns show as it’s supposed to.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

type Config {
    id: string;
    show: boolean;
};

KeysOfType<Config, boolean>  // <-- Result: ('show')

But I can’t get it to work correctly when the field is optional or based a union

export type Config = {
    id: string;
    optional?: boolean;
    union: boolean | string
    show: boolean;
};

KeysOfType<Config, boolean>  // <-- Result: ('show' | undefined). Expected: ('show' | 'optional' | 'union').

KeysOfType<Config, string>   // -< Result: ('id' | undefined). Expected: ('id' | 'union')

KeysOfType<Config, boolean | undefined>  // <-- Result: ('optional' | 'show' | undefined). Expected: ('optional')

The result I’m expecting from that would be 'show' | 'optional' | 'union' or at least not having undefined as there’s no key called undefined

How can I achieve this?

>Solution :

As far as I can tell from your requirements, inverting the extends clause and removing the optional modifier (-?) from your index type should get you the results you want:

export type KeysOfType<T, U> = {
  [K in keyof T]-?: U extends T[K] ? K : never
}[keyof T];

export type Object = {
    id: string;
    optional?: boolean;
    union: boolean | string
    show: boolean;
};

type X = KeysOfType<Object, boolean>; // "optional" | "union" | "show"
type Y = KeysOfType<Object, string>; // "id" | "union"
type Z = KeysOfType<Object, boolean | undefined>; // "optional" | "union" | "show"

If you want to use unions, I think you do need to decide in which direction you need the matching to work, i.e. whether it’s

  • U extends T[K] ? K : never; or
  • T[K] extends U ? K : never; or
  • U extends T[K] ? T[K] extends U ? K : never : never
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading