In my code, I've created a type definition that allows me to traverse an object using an array of strings or indices representing the keys of the object or nested arrays:
export type PredicateFunction<ArrayType> = (array: ArrayType, index?: number) => boolean;
export type IndexOrPredicateFunction<Type> = number | PredicateFunction<Type>;
export type StatePathKey = IndexOrPredicateFunction<any> | string;
export type StatePath<Obj, Path extends (string | IndexOrPredicateFunction<any>)[] = []> =
object extends Obj
? Path
: Obj extends object
? (Path |
// Check if object is array
(Obj extends readonly any[] ?
// ...when array only allow index or PredicateFunction
StatePath<Obj[number], [...Path, IndexOrPredicateFunction<Obj[number]>]>
// ...when object generate type of all possible keys
: { [Key in string & keyof Obj]: StatePath<Object[Key], [...Path, Key]> }[string & keyof Obj]))
: Path;
This setup works well with an interface like this:
interface State1 {
test: {
nestedTest: boolean
}
}
where we can use it like this:
const t1: StatePath<State1> = ['test', 'nestedTest'];
However, it encounters issues when dealing with optional properties like in this interface:
interface State2 {
test: {
nestedTest?: boolean
}
}
I'm struggling to find a solution for this. I've tried using -?
on the type without success. Any suggestions on how to overcome this challenge? You can try reproducing the issue in this TypeScript playground here.