|
/* |
|
Lowdb allows retrieving values using indexes like `a[0].b`. For that we can use the following `ValueType` instead. |
|
|
|
Note that using key as: |
|
1. `""` (empty) |
|
2. `"..."` (has multiple dots in b/w) |
|
3. `"a.b."`(starts/ends with dot(s)) |
|
4. `"a.b[]"` (empty index) |
|
5. `"a.b[cd]"` (non-numeric index) |
|
6. `"a.b[2]"` (expecting a tuple value) |
|
|
|
will silently fail. |
|
*/ |
|
|
|
type ValueType< |
|
S extends string, |
|
R extends Record<string, any> | any[] |
|
> = |
|
S extends "" |
|
? R |
|
: S extends `.${infer Rest}` |
|
? ValueType<Rest, R> |
|
: S extends `[${infer Idx}]${infer Rest}` |
|
? R extends any[] |
|
? ValueType<Rest, R[0]> |
|
: never |
|
: R extends Record<string, any> |
|
? S extends `${infer Key}.${infer Rest}` |
|
? Key extends `${infer ActualKey}[${infer ActualRest}]` |
|
? ActualKey extends "" |
|
? ValueType<`[${ActualRest}].${Rest}`, R> |
|
: ValueType<`[${ActualRest}].${Rest}`, R[ActualKey]> |
|
: ValueType<Rest, R[Key]> |
|
: S extends `${infer ActualKey}[${infer ActualRest}]` |
|
? ValueType<`[${ActualRest}]`, R[ActualKey]> |
|
: R[S] |
|
: never |
|
|
|
/* |
|
You can make over `ValueType` more strict by passing into following validation checks. It resolves 2, 3 and 4. |
|
*/ |
|
|
|
type FailOnMoreThanOneDot< |
|
S extends string | never |
|
> = S extends `${infer A}..${infer B}` ? never : S; |
|
type FailOnDotAtSides<S extends string | never> = S extends |
|
| `.${infer A}` |
|
| `${infer A}.` |
|
? never |
|
: S; |
|
type FailOnEmptyIndex< |
|
S extends string | never |
|
> = S extends `${infer A}[]${infer B}` ? never : S; |
|
|
|
// Use this over `ValueType` if you want validation checks too |
|
// Make sure to update occurences of `ValueType` to `WrappedValueType` inside `Dotted` |
|
type WrappedValueType< |
|
S extends string, |
|
R extends Record<string, any> |
|
> = ValueType<FailOnMoreThanOneDot<FailOnDotAtSides<FailOnEmptyIndex<S>>>, R>; |