I have an abstract class:
abstract class Foo {
abstract bar(): string;
}
I have some classes that extend Foo
:
class Foo1 extends Foo {
bar(): string { return 'foo1'; }
}
class Foo2 extends Foo {
bar(): string { return 'foo2'; }
}
I have another class that I want to proxy all methods of Foo
to a Foo
. This actually works fine, if I define all methods of Foo
on this class. But I would rather not do that. I would prefer to have the methods of Foo
defined on Foo
and the compiler to know that FooProxy
also implements those methods without actually having to implement them. Is this possible? The Proxy class looks something like this:
class FooProxy {
public foo: Foo;
constructor(foo: Foo) {
this.foo = foo;
let handler = {
get: function(target: FooProxy, prop: string, receiver: any) {
if(Foo.prototype[prop] !== null) {
return target.foo[prop];
}
return Reflect.get(target, prop, receiver);
}
}
return new Proxy(this, handler);
}
}
Example:
let f = new Foo1();
let fp = new FooProxy(f);
fp.bar();
Output:
error TS2339: Property 'bar' does not exist on type 'FooProxy'.
This program actually runs in the playground, but tsc
does not emit anything. I just need to trick the compiler some how...
I don't think in this case a class is the best approach you can just use a function to create the proxy and all will work as expected:
function createFooProxy(foo:Foo) : Foo { // Proxy<Foo> is compatible with Foo
let handler = {
get: function(target: Foo, prop: keyof Foo, receiver: any) {
if(Foo.prototype[prop] !== null) {
return foo[prop];
}
return Reflect.get(target, prop, receiver);
}
}
return new Proxy(foo, handler);
}
If you are set on using the class approach, you can fake a base class:
function fakeBaseClass<T>() : new() => Pick<T, keyof T>{ // we use a pick to remove the abstract modifier
return class {} as any
}
class FooProxy extends fakeBaseClass<Foo>(){
private foo: Foo; // I would make this private as it is not really accessible on what the constructor of FooProxy returns (maybe remove it as I see no use for it)
constructor(foo: Foo) {
super();
this.foo = foo;
let handler = {
get: function(target: FooProxy, prop: keyof Foo, receiver: any) {
if(Foo.prototype[prop] !== null) {
return target.foo[prop];
}
return Reflect.get(target, prop, receiver);
}
}
return new Proxy(this, handler);
}
}