Last active
September 13, 2021 20:31
-
-
Save esmevane/c2a85eaff8fd0589279b6cc6f7893ef9 to your computer and use it in GitHub Desktop.
[ Typescript ]: Strongly typed, filterable keypaths
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type GetKeypaths< | |
GivenType, | |
Filter extends string = '___!!!PLACEHOLDER!!!___' | |
> = GivenType extends object | |
? keyof GivenType extends string | |
? keyof GivenType extends Filter | |
? GetKeypaths<GivenType[keyof GivenType], Filter> | |
: | |
| keyof GivenType | |
| `${keyof GivenType}.${GetKeypaths< | |
GivenType[keyof GivenType], | |
Filter | |
>}` | |
: never | |
: never; | |
type GetStates<GivenType> = GetKeypaths<GivenType, 'states'>; | |
type Schema = { | |
states: { | |
one: { | |
states: { | |
two: {}; | |
three: { | |
states: { | |
four: null; | |
}; | |
}; | |
five: { | |
states: { | |
six: { | |
states: { | |
seven: 'spork'; | |
}; | |
}; | |
}; | |
}; | |
}; | |
}; | |
}; | |
}; | |
type K001 = GetStates<Schema>; | |
// Right now, this returns the following: | |
// type K001 = | |
// | "one" | |
// | "one.two" | |
// | "one.three" | |
// | "one.five" | |
// | "one.two.four" | |
// | "one.two.six" | |
// | "one.two.six.seven" | |
// | "one.three.four" | |
// | "one.three.six" | |
// | "one.three.six.seven" | |
// | "one.five.four" | |
// | "one.five.six" | |
// | "one.five.six.seven" | |
// But, it _should_ return this: | |
// type K001 = | |
// | "one" | |
// | "one.two" | |
// | "one.three" | |
// | "one.five" | |
// | "one.three.four" | |
// | "one.five.six" | |
// | "one.five.six.seven" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Looks like the correct type is:
This changes what happens a bit internally. Instead of just distributing out keys, it goes into the object at each level and updates the object properties to contain the keypath, then unravels that object and returns the values. This makes it impossible to get that odd distribution bug (since we're only modifying things that are proven to exist via the mapped type logic).
Found the way to this answer by adapting the response to this overflow ticket: https://stackoverflow.com/questions/65332597/typescript-is-there-a-recursive-keyof