Reputation: 11
Suppose I have the following interface:
interface Foo {
x: {
x1: string;
x2: {
x3: number;
}
};
}
I want to write a class where a function automatically figures out the valid arguments based on the type.
For example:
const x = someNewClass();
x
.ref('x')
.ref('x1 | x2') // we pass either x1 or x2
.ref('x3').getAsPath(); // if we pass x2, we see x3, otherwise undefined
The values I've written should auto-complete, and the function should return the path: x/x2/x3'
;
I don't know typescript very well -- I don't even know if this is possible! However, I got this far (which admittedly isn't very far):
class SomeHelperClass<T> {
public ref(d: keyof T) {
// can we return a new instance of a this class initialized with
// T taken as a partial of the original type starting from `d`?
return this;
}
public getAsPath() {
// ...
}
}
class Test extends SomeHelperClass<Foo> {}
const t = new Test();
t.ref('x').ref('...');
The first ref call of course works, but I am completely lost after that.
Upvotes: 0
Views: 53
Reputation: 11
Thanks to @SergiuParaschiv's link, I found a working solution for my exact issue. I am sharing the code here in case the github repos or the references disappear for any reason.
interface PathResult<T> {
<TSubKey extends keyof T>(key: TSubKey): PathResult<T[TSubKey]>;
/**Gets the resulting path */
path: string[];
}
/**
* Create a deep path builder for a given type
*/
export function path<T>() {
/**Returns a function that gets the next path builder */
function subpath<T, TKey extends keyof T>(parent: string[], key: TKey): PathResult<T[TKey]> {
const newPath = [...parent, key];
const x = (<TSubKey extends keyof T[TKey]>(subkey: TSubKey) => subpath<T[TKey], TSubKey>(newPath, subkey)) as PathResult<T[TKey]>;
x.path = newPath;
return x;
}
return <TKey extends keyof T>(key: TKey) => subpath<T, TKey>([], key);
}
To see the solution in action, please visit the author's repository.
Thanks again Sergiu!
Upvotes: 1