如何使用与T不同的代理<t>作为参数?

时间:2018-05-30 10:56:26

标签: javascript typescript ecmascript-6

我处在一种情况,我想使用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();

这“有效”。问题是我正在使用打字稿。而且,由于Proxy类型定义,我们无法执行类似

的操作
new Proxy<Foo>([new Foo(), new Foo()], handler)

因为它产生以下错误:

  

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

有没有办法实现这一目标;没有丢失类型检查?

3 个答案:

答案 0 :(得分:3)

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

如果您使用的是模块系统,则需要重新声明全局ProxyConstructor才能使其正常工作:

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

答案 1 :(得分:1)

您可以编辑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;

然后将Proxy用法修改为以下内容:

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];
    },
});

答案 2 :(得分:0)

一个简单的解决方案是创建一个这样的工厂:

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

通过这种方式,您可以使用可重复使用且类型安全的平衡器而不会泄露任何声明。