Let's assume we have following constant:
const something = {
foo: {
bar: {
num: 67,
str: 'str',
},
},
some: {
prop: 12,
},
topProp: 25,
};
The Task:
Implement typechecking for following deep property access function
/**
* @example
* getByPath('foo/bar/str'); // returns 'str'
*
* @example
* getByPath('topProp'); // returns 25
*
* @example
* getByPath('some/prop'); // returns 12
*/
const getByPath = (path: ComputedUnionType) => {<unrelated-code-magic>};
// Where
type ComputedUnionType = 'foo/bar/num' | 'foo/bar/str' | 'some/prop' | 'topProp';
// or even better
type ComputedUnionType<typeof some> = 'foo/bar/num' | 'foo/bar/str' | 'some/prop' | 'topProp';
const getByPath = <T>(path: ComputedUnionType<T>) => ...
What I did?
- Implemented function on getting array of valid paths, but it returns array of simple strings(obviously -_-), so couldn't find any way to use it to enforce types
- Read a bunch of articles on enum types, resulting in conslustion that enum types will not help me here, because their property values can only be computed numbers, not strings (and probably they won't help anyway, because their properties itself can not be generated on fly)
- Stumbled across this answer on implementing tuples typechecking, but failed to somehow make use of it in my case. It is pretty interesting read, but in general provided solution juggles with existing union types and keys but never computes new ones.
Guesses
- Maybe it could be a type that calls itself recursively like deep partial or something like that
type DeepPartial<T> = {
[P in keyof T]?: DeepPartial<T[P]>;
};
- Maybe there is some way to achieve it from the bottom with generic types, taking keyof bar, keyof foo and so on.