The title might be a bit misleading, but I'm struggling to articulate my issue.
I aim to pass a generic class (or just the class body) as an argument to a function. The provided class should then infer its generics automatically.
class Builder<EXT, INT = EXT> {
// some builder stuff that alters the generic T
withBar(): Builder<EXT, INT & { bar: string }> {
return this as any;
}
// here lies the challenge:
build(clazz: MyClass<INT>): MyClass<EXT> {
return wrap(clazz); // this method already exists and functions correctly
}
}
Usage:
const builder = new Builder<{ foo: number }>();
// EXT = { foo: number }, INT = { foo: number }
builder = builder.withBar();
// EXT = { foo: number }, INT = { foo: number, bar: string }
builder.build(class { /* here I should be able to access this.foo and this.bar */ });
// Here I just want to provide the class body,
// because I don't want to type all the generics again.
// I don't want to specify `MyClass<?>`,
// because the correct type is already specified within the Builder
As an (ugly) "workaround," I discovered a method to provide all class methods individually and then construct a class from them. Something like this:
class Builder<EXT, INT = EXT> {
build(args: {method1?: any, method2?: any}): MyClass<EXT> {
class Tmp {
method1() {
return args.method1 && args.method1(this);
}
method2(i: number) {
return args.method2 && args.method2(this);
}
}
return wrap(Tmp);
}
}
But it's quite messy.
Essentially, I simply want to provide the class body to the build
method. Then this method would create a class from it, invoke wrap
, and return the result.
Is there a way to achieve this?
EDIT: Another attempt to clarify my issue:
Currently, I need to use the code in this manner:
builder.build(class extends AbstractClass<{ foo: number, bar: string }> {
private prop: string;
init() {
this.prop = this.data.foo // provided by AbstractClass
? 'foo'
: 'bar'
}
getResult() {
return {
foo: this.prop,
bar: this.data.bar // provided by AbstractClass
}
}
})
As depicted, I have to specify the generics of AbstractClass
. I prefer not to specify the type since builder
already knows it.
I only wish to provide the body of the class without reiterating the generic type. Something akin to this:
builder.build(class extends AbstractClass<infer the type magically!> {
...
getResult() {
return { this.data.foo }
}
})
Or even this:
builder.build(class {
...
getResult() {
return { this.data.foo }
}
})