I'm in a situation where I want to use Proxy
, to "load balance" between a list of class.
A naive example of what I'm trying to do is the following :
class Foo {
constructor(private msg: string) {}
foo() {
console.log(this.msg);
}
}
// @ts-ignore
const proxy: Foo = new Proxy([new Foo('foo'), new Foo('bar')], {
get: (o, key) => {
const client = o[Math.floor(Math.random() * o.length)];
console.log(client, key);
return client[key];
},
});
proxy.foo();
This "works". The problem is that I'm using typescript. And, due to the Proxy
type definition we can't do something like
new Proxy<Foo>([new Foo(), new Foo()], handler)
as it produce the following error :
Argument of type 'Foo[]' is not assignable to parameter of type 'Foo'.
Is there a way to achieve this ; without loosing type checking ?
I'm in a situation where I want to use Proxy
, to "load balance" between a list of class.
A naive example of what I'm trying to do is the following :
class Foo {
constructor(private msg: string) {}
foo() {
console.log(this.msg);
}
}
// @ts-ignore
const proxy: Foo = new Proxy([new Foo('foo'), new Foo('bar')], {
get: (o, key) => {
const client = o[Math.floor(Math.random() * o.length)];
console.log(client, key);
return client[key];
},
});
proxy.foo();
This "works". The problem is that I'm using typescript. And, due to the Proxy
type definition we can't do something like
new Proxy<Foo>([new Foo(), new Foo()], handler)
as it produce the following error :
Argument of type 'Foo[]' is not assignable to parameter of type 'Foo'.
Is there a way to achieve this ; without loosing type checking ?
Share Improve this question edited May 30, 2018 at 11:08 Niladri 5,9622 gold badges26 silver badges43 bronze badges asked May 30, 2018 at 10:56 Rémi RousseletRémi Rousselet 277k89 gold badges553 silver badges451 bronze badges 1-
as
works but may or may not satisfy "without loosing type checking" – KTibow Commented Dec 28, 2024 at 2:17
3 Answers
Reset to default 8You don't need to change the existing definitions, you can just augment them.
If you are using a module system, you need to redeclare the ProxyConstructor
in global for it to work:
declare global {
interface ProxyConstructor {
new <TSource extends object, TTarget extends object>(target: TSource, handler: ProxyHandler<TSource>): TTarget;
}
}
const proxy: Foo = new Proxy<Foo[], Foo>([new Foo('foo'), new Foo('bar')], {
get: (o, key) => {
const client = o[Math.floor(Math.random() * o.length)];
console.log(client, key);
return client[key];
},
});
proxy.foo();
A straightforward solution is to create a factory like this:
function balance<T>(instances: Array<T>): T {
return new Proxy<any>({}, {
get: (o, key) => {
const client = instances[Math.floor(Math.random() * instances.length)];
console.log(client, key);
return client[key];
},
}) as T;
}
const proxy = balance([new Foo('foo'), new Foo('bar')]);
proxy.foo();
That way you have a reusable and typesafe balancer without promising any declaration.
You can edit Proxy
type definition to allow a different type from it's parameter type.
interface ProxyConstructor {
revocable<T extends object, S extends object>(
target: T,
handler: ProxyHandler<S>,
): { proxy: T; revoke: () => void };
new <T extends object>(target: T, handler: ProxyHandler<T>): T;
new <T extends object, S extends object>(target: S, handler: ProxyHandler<S>): T;
}
declare var Proxy: ProxyConstructor;
Then modify your Proxy
usage to the following :
const proxy: Foo = new Proxy<Foo, Foo[]>([new Foo('foo'), new Foo('bar')], {
get: (o, key) => {
const client = o[Math.floor(Math.random() * o.length)];
console.log(client, key);
return client[key];
},
});