Website-Suche

javascript - Wie verwendet man Proxy<T> mit einem anderen Typ als T als Argument?


Ich befinde mich in einer Situation, in der ich Proxy verwenden möchte, um zwischen einer Liste von Klassen zu "Lastenausgleich".

Ein naives Beispiel für das, was ich zu tun versuche, ist das Folgende:

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();

Dies „funktioniert“. Das Problem ist, dass ich TypeScript benutze. Und aufgrund der Proxy-Typdefinition können wir nicht so etwas machen wie

new Proxy<Foo>([new Foo(), new Foo()], handler)

da es den folgenden Fehler erzeugt:

Argument des Typs 'Foo[]' kann dem Parameter des Typs 'Foo' nicht zugewiesen werden.

Gibt es eine Möglichkeit, dies zu erreichen, ohne die Typüberprüfung zu verlieren?

Antwort #1

Sie müssen die bestehenden Definitionen nicht ändern, Sie können sie einfach ergänzen.

Wenn Sie ein Modulsystem verwenden, müssen Sie den ProxyConstructor global neu deklarieren, damit es funktioniert:

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();

Antwort #2

Eine einfache Lösung besteht darin, eine Fabrik wie diese zu erstellen:

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();

Auf diese Weise haben Sie einen wiederverwendbaren und typsicheren Balancer, ohne eine Deklaration zu kompromittieren.

Verwandte Artikel