It's trivial if you have 3 subtypes to put them together into one large one:
type Strings = {
a: string;
b: string;
c: string;
...
};
type Numbers = {
one: number;
two: number;
...
};
type Booleans = {
True: boolean;
...
};
type All = Strings & Numbers & Booleans;
but what if you start with the combined Type?
type All = {
a: string;
b: string;
c: string;
one: number;
two: number;
True: boolean;
...
}
Is it possible to split All into the 3 sub types above based on the type of the values for each key?
I thought maybe this could work but it does not
type noNumbers= Exclude<All, { [key: string]: number }>;
We can make custom type level function in order to achieve or omitting by value type or picking by value type. Below both options:
The key to the success is how union type treads
never, its neutral element for|operator, it means it is just skipped and has no impact at the type. Consider small proove:Thanks to that we can use
neverin order to skip some keys. That is exactly visible in this part:What is happening exactly is - we create mapped type with values equal keys, but only if the value type is ok, if not we use
never, and after that we take these values by index[keyof T]. Lets recap step by step what is happening:key-> (key | never)[keyof T]gathers all value type as union (andneverelements are not considered)neverPickorOmit