There's nothing easy you can do here with your current querying approach. It's ambiguous which property you're selecting, so there's going to be no easy way to get the right path. It's not that your code is 'wrong' now as such, it's just that there's two possible correct answers, and it's picked one arbitrarily.
You can change the rules on which of the possible keys it picks, but there are no sensible rules that will reliably get you the right single answer. Alternatively you could return all the possible answers, and have an ambiguous path, but it doesn't seem like that does what you're looking for.
There might be one option by doing crazy things like parsing the function provided with Esprima or even regular expressions to work out which properties are being grabbed, but it's generally going to be a bad idea. That's likely to be complex and fragile, unreliable unless you can guarantee the exact shape of the code you'll be provided in To()
, and run pretty slowly too.
If you do want to be able to select properties like this and know the path used for certain, you'll have to give your To
function the key of the property, not just a function to get the value it holds. It's a less elegant API, but it's the only sensible way you're going to get the behaviour you're looking for:
class NavigableObject<T> {
constructor(private obj: T, private path: string[] = []) { }
To<R>(p: string): NavigableObject<R> {
return new NavigableObject<R>(this.obj[p],
this.path.concat(p));
}
getPath() {
return this.path;
}
}
let test = {
a: {
a1: 1,
a2: 1
},
b: {
b1: 1,
b2: 2
}
}
let navigableTest = new NavigableObject(test);
navigableTest.To('b').To('b2').getPath();
navigableTest.To('a').To('a2').getPath();
In future it might be possible to do this with type safety in TypeScript, but not right now. This PR is looking into exactly these issues, but it's still under some discussion yet, so there'll be a while until it's implemented. Note that it's still proposing the string-based approach from the example above, it's just the type system will check that string constants are valid property names for the types used.