Reputation: 9324
I'm not quite sure of the 'name' for the type of object that I'm creating. I'm calling it a tree because it looks similar to a nested tree without the relationships. Essentially I want an object with nested definitions like so
{
test1: OptionsInterface,
test2: {
test3: OptionsInterface,
test4: {
test5: OptionsInterface,
},
},
}
So the first level can be either OptionsInterface
or {[s: string]: OptionsInterface}
Is there a way to use this on every 'level' of the object?
I've tried defining the above like so:
export default class ApiClient {
constructor(options: {[s: string]: OptionsInterface | {[s: string]: OptionsInterface}}) {}
But this is only going to be 2 deep right? Is there a way I can define my example object without having to manually add every depth?
use case
I want to be able to call my class like so
api = new ApiClient(routeSchema);
await api.call('test2.test4.test5', params);
in call:
async call(config: string, variables: object = {}): Promise<Response> {
const options = get(this.configuration, config);
if (options === undefined) {
throw new ConfigNotDefinedExpection(config);
}
return await this.callWithOptions(options, variables);
}
Where callWithOptions
expects an OptionsInterface
Upvotes: 1
Views: 1851
Reputation: 329248
Sure, you can do that.
type NestableOptionsInterface = OptionsInterface | { [k: string]: NestableOptionsInterface }
That says a NestableOptionsInterface
is either an OptionsInterface
or a dictionary whose keys are anything you want and whose values are NestedOptionsInterface
. So it's a recursive defintion. Let's test it:
class Foo {
constructor(options: NestableOptionsInterface) { }
}
declare const optionsInterface: OptionsInterface;
new Foo(optionsInterface); // okay
new Foo({ a: optionsInterface, b: { c: optionsInterface } }); // okay
new Foo({ a: { b: { c: { d: { e: optionsInterface } } } } }); // okay
new Foo("whoops"); // error
new Foo({ a: optionsInterface, b: { c: "whoops" } }); // error
Looks good.
If you want to maintain the type of the actual constructor argument, you can use generics like this:
class Foo<O extends NestableOptionsInterface> {
constructor(options: O) { }
}
declare const optionsInterface: OptionsInterface;
new Foo(optionsInterface); // Foo<OptionsInterface>
new Foo({ a: optionsInterface, b: { c: optionsInterface } }); // Foo<{ a: OptionsInterface, b:{c: OptionsInterface}}>
new Foo({ a: { b: { c: { d: { e: optionsInterface } } } } }); // Foo<{ a:{b:{c:{d:{e: OptionsInterface}}}}}>
Hope that helps. Good luck!
Upvotes: 5