Skip to content

Commit 7ec197a

Browse files
authored
feat(type): add DeepPick utility type (#146)
* feat(type): add `DeepPick` utility type * chore: update `DeepPick` utility type
1 parent 19b203e commit 7ec197a

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

src/object-types.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,3 +540,26 @@ export type Get<T, K extends string> = K extends keyof T
540540
: K extends `${infer Char extends keyof T & string}.${infer Substr}`
541541
? Get<T[Char], Substr>
542542
: never
543+
544+
/**
545+
* Picks the properties of an object at any depth based on the provided pattern.
546+
*
547+
* @example
548+
* interface User {
549+
* name: string,
550+
* address: {
551+
* street: string,
552+
* avenue: string
553+
* }
554+
* }
555+
*
556+
* // Expected: { address: { street: string } }
557+
* type UserPick = DeepPick<User, "address.street">
558+
*/
559+
export type DeepPick<Obj, Pattern> = Pattern extends `${infer Left}.${infer Right}`
560+
? Left extends keyof Obj
561+
? DeepPick<Obj[Left], Right>
562+
: unknown
563+
: Pattern extends keyof Obj
564+
? Obj[Pattern]
565+
: unknown

test/object-types.test.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,3 +385,44 @@ describe("Get", () => {
385385
>().toEqualTypeOf<number>()
386386
})
387387
})
388+
389+
describe("DeepPick", () => {
390+
test("Pick properties from nested objects", () => {
391+
type Obj = {
392+
foo: string
393+
bar: number
394+
foobar: {
395+
foofoo: number
396+
barbar: boolean
397+
foo: {
398+
bar: string
399+
foobar: number
400+
barfoo: {
401+
foobar: string
402+
bar: number
403+
}
404+
}
405+
}
406+
}
407+
408+
expectTypeOf<utilities.DeepPick<Obj, "foo">>().toEqualTypeOf<string>()
409+
expectTypeOf<utilities.DeepPick<Obj, "bar">>().toEqualTypeOf<number>()
410+
expectTypeOf<utilities.DeepPick<Obj, "foobar">>().toEqualTypeOf<{
411+
foofoo: number
412+
barbar: boolean
413+
foo: {
414+
bar: string
415+
foobar: number
416+
barfoo: {
417+
foobar: string
418+
bar: number
419+
}
420+
}
421+
}>()
422+
expectTypeOf<utilities.DeepPick<Obj, "foobar.barbar">>().toEqualTypeOf<boolean>()
423+
expectTypeOf<utilities.DeepPick<Obj, "foobar.foo.barfoo">>().toEqualTypeOf<{
424+
foobar: string
425+
bar: number
426+
}>()
427+
})
428+
})

0 commit comments

Comments
 (0)