Skip to content

Commit 84c7c84

Browse files
committed
chore: add test
1 parent 16cb1ea commit 84c7c84

File tree

2 files changed

+80
-13
lines changed

2 files changed

+80
-13
lines changed
Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,30 @@
1+
type IsAny<T> = 0 extends 1 & T ? true : false
2+
3+
type Clean<T> = Exclude<T, undefined | null>
4+
15
type CollapsibleKeys<T, TPrefix extends string = ''> =
2-
T extends ReadonlyArray<infer U>
3-
?
4-
| (TPrefix extends '' ? '' : TPrefix)
5-
| CollapsibleKeys<U, `${TPrefix}[${number}]`>
6-
: T extends object
6+
IsAny<T> extends true
7+
? TPrefix extends ''
8+
? never
9+
: TPrefix
10+
: T extends ReadonlyArray<infer U>
711
?
812
| (TPrefix extends '' ? '' : TPrefix)
9-
| {
10-
[K in Extract<keyof T, string>]: CollapsibleKeys<
11-
T[K],
12-
TPrefix extends '' ? `${K}` : `${TPrefix}.${K}`
13-
>
14-
}[Extract<keyof T, string>]
15-
: never
13+
| CollapsibleKeys<U, `${TPrefix}[${number}]`>
14+
: T extends object
15+
?
16+
| (TPrefix extends '' ? '' : TPrefix)
17+
| {
18+
[K in Extract<keyof T, string>]: CollapsibleKeys<
19+
T[K],
20+
TPrefix extends '' ? `${K}` : `${TPrefix}.${K}`
21+
>
22+
}[Extract<keyof T, string>]
23+
: never
1624

1725
export type CollapsiblePaths<T> =
18-
CollapsibleKeys<T> extends string ? CollapsibleKeys<T> : never
26+
CollapsibleKeys<Clean<T>> extends infer P
27+
? P extends string
28+
? P
29+
: never
30+
: never

packages/devtools-ui/tests/deep-keys.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { describe, expectTypeOf, it } from 'vitest'
2+
3+
// types
14
import type { CollapsiblePaths } from '../src/utils/deep-keys'
25

36
type WithDeeplyNestedObject = {
@@ -65,3 +68,55 @@ type WithGeneric<TData> = {
6568
}
6669

6770
type _WithGeneric = CollapsiblePaths<WithGeneric<{ a: { b: string } }>>
71+
72+
describe('deep-keys', () => {
73+
it('should type deeply nested keys', () => {
74+
expectTypeOf<_DeeplyNestedObject>().toEqualTypeOf<
75+
| ''
76+
| 'a'
77+
| 'a.b'
78+
| 'a.b.c'
79+
| 'a.b.c.d'
80+
| 'a.b.c.d.e'
81+
| 'a.b.c.d.e.f'
82+
| 'a.b.c.d.e.f.g'
83+
| 'a.b.c.d.e.f.g.h'
84+
| 'a.b.c.d.e.f.g.h.i'
85+
>()
86+
})
87+
88+
it('should handle any', () => {
89+
expectTypeOf<_Any>().toEqualTypeOf<'' | 'errors'>()
90+
})
91+
92+
it('should handle array recursion', () => {
93+
expectTypeOf<_ArrayRecursion>().toEqualTypeOf<
94+
| ''
95+
| 'arr'
96+
| `arr[${number}]`
97+
| `arr[${number}][${number}]`
98+
| `arr[${number}][${number}][${number}]`
99+
| `arr[${number}][${number}][${number}][${number}]`
100+
>()
101+
})
102+
103+
it('should handle undefined', () => {
104+
expectTypeOf<_WithUndefined>().toEqualTypeOf<
105+
'' | 'status' | 'status.error'
106+
>()
107+
})
108+
109+
it('should handle unknown', () => {
110+
expectTypeOf<_WithUnknown>().toEqualTypeOf<''>()
111+
})
112+
113+
it('should handle realistic state', () => {
114+
expectTypeOf<_WithRealisticState>().toEqualTypeOf<
115+
'' | 'errors' | 'errorMap' | `errors[${number}]` | `errorMap.${string}`
116+
>()
117+
})
118+
119+
it('should handle generics', () => {
120+
expectTypeOf<_WithGeneric>().toEqualTypeOf<'' | 'generic' | 'generic.a'>()
121+
})
122+
})

0 commit comments

Comments
 (0)