Hello there, I am in charge of maintaining the ts-essentials project. Within our toolkit, we have a handy utility type known as DeepPick that could be of assistance in your specific situation.
I want to emphasize that utilizing this approach would be most advantageous when a more generic solution is needed, particularly if you find yourself needing it in multiple places with varying levels. Otherwise, feel free to disregard this and opt for the approach involving Pick
and mapped types.
- If you want to experiment with the
ts-essentials
utility type in the TypeScript Playground, visit - https://tsplay.dev/NdyA6m
- To view the complete extracted utility type in the TypeScript Playground (including an example at the end), follow this link - https://tsplay.dev/mZy49N
- For a simplified version of the extracted utility type (without autocomplete and fewer edge cases) in the TypeScript Playground, click here - https://tsplay.dev/N7Q14W
You can make use of this type to specifically retrieve the values you require:
type newType = {
a: string,
b: string,
c: {
x: string,
y: string,
z: string,
},
}
type OnlyCY = DeepPick<
// ^? { c: { y: string } }
newType,
{
c: {
y: never
}
}
>;
The simplified solution appears concise and elegant:
type Primitive = string | number | boolean | bigint | symbol | undefined | null;
type Builtin = Primitive | Function | Date | Error | RegExp;
type AnyRecord = Record<string, any>;
export type DeepPick<Type, Filter> = Type extends Builtin
? Type
: Filter extends AnyRecord
? {
// iterate over keys of Type, which keeps the information about keys: optional, required or readonly
[Key in keyof Type as Key extends keyof Filter ? Key : never]: Filter[Key & keyof Filter] extends true
? Type[Key]
: Key extends keyof Filter
? DeepPick<Type[Key], Filter[Key]>
: never;
}
: never;
If you have any questions, feel free to reach out to me. Happy coding!