I would like to implement deep pick in typescript.
My example code is:
interface TestBook {
id: string;
name: string;
}
interface TestUser {
id: string;
email: string;
books: TestBook[];
}
I and I would like to use deep pick like:
const foo: DeepPick<TestUser, 'id' | 'books.name'> = {...
/*
{
id: ..
books: [{name: ...}]
}
*/
Problem: There is only Pick
in standard typescript and there is no library implement this DeepPick
.
How can I do it? Which technic should I use?
I tried to find on google and SO.
CodePudding user response:
Let's first define some utility types to get the "head" or "tail" of a path:
type Head<T extends string> = T extends `${infer First}.${string}` ? First : T;
type Tail<T extends string> = T extends `${string}.${infer Rest}` ? Rest : never;
Then our DeepPick can take the heads of the paths and then deep pick the tail:
type DeepPick<T, K extends string> = T extends object ? {
[P in Head<K> & keyof T]: T[P] extends readonly unknown[] ? DeepPick<T[P][number], Tail<Extract<K, `${P}.${string}`>>>[] : DeepPick<T[P], Tail<Extract<K, `${P}.${string}`>>>
} : T
If it's not an object, we shouldn't do anything to it. Inside the mapped type, I also added a case for arrays.