代码之家  ›  专栏  ›  技术社区  ›  Rémi Rousselet

如何使用类型不同于T的Proxy<T>作为参数?

  •  4
  • Rémi Rousselet  · 技术社区  · 8 年前

    我现在的处境是我想使用 Proxy ,以实现类列表之间的“负载平衡”。

    下面是我试图做的一个天真的例子:

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

    这“管用”。问题是我用的是打字脚本。而且,由于 代理 类型定义我们不能这样做

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

    因为它会产生以下错误:

    “Foo[]”类型的参数不能分配给“Foo”类型的参数。

    有没有办法做到这一点;不放松类型检查?

    3 回复  |  直到 8 年前
        1
  •  3
  •   Titian Cernicova-Dragomir    8 年前

    您不需要更改现有的定义,只需对其进行扩充即可。

    如果您使用的是模块系统,则需要重新声明 ProxyConstructor 在全球it运作中:

    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();
    
        2
  •  1
  •   Rémi Rousselet    8 年前

    你可以编辑 Proxy 类型定义,以允许不同于其参数类型的类型。

    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;
    

    然后修改你的 代理 用法如下:

    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];
        },
    });
    
        3
  •  0
  •   a better oliver    8 年前

    一个简单的解决方案是创建如下工厂:

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

    这样,您就拥有了一个可重用且类型安全的平衡器,而不会影响任何声明。