我正在开发一个简单的RPC客户端/服务器库供我内部使用。我想用一个界面来描述客户端和服务器,所以我可以在我的通用应用程序中在服务器和浏览器之间共享它们。
服务器很简单,服务只是扩展我的Service类并实现描述API的接口。
客户端将被实现为ES6代理,只需将所有方法调用发送到服务器,我想要强烈键入它以及服务类。 我需要ServiceClient类型的实例来获取它的类型参数的所有方法和属性,无论它是什么。
我正在考虑这种语法:
interface Api
{
foo(): boolean;
}
class MyService extends Service implements Api
{
public foo(): boolean { return true; }
}
// usage
let result = (new ServiceClient<Api>()).foo(); // type of result is inferred, I get an error if I try to use an undefined method, arguments are type checked...
我试图浏览一些类似的工作类型,但找不到办法。谢谢你的帮助。
答案 0 :(得分:1)
我希望我明白你在问什么。
您不能在运行时使用泛型参数(T
),因此您无法动态创建实现T
中所有方法的代理对象。
你可以做的是这样的事情:
interface Api {
foo(): boolean;
}
abstract class Service {}
class MyService extends Service implements Api {
public foo(): boolean { return true; }
}
const myService = new MyService();
const ServiceClient = {} as Api;
for (let key in myService) {
if (typeof myService[key] === "function" && key !== "constructor") {
ServiceClient[key] = function() {
return myService[key].apply(myService, arguments);
}
}
}
let result = ServiceClient.foo(); // true
我所做的是创建了一个MyService
的实例,然后我创建了一个对象,它将成为此myService
的代理,此代理ServiceClient
首先被创建为一个空对象。
然后我迭代MyService
实例的属性,并为每个函数(不是构造函数)我在代理对象上创建一个具有相同名称的函数,当调用每个函数然后等效函数在myService
中调用。
如果我理解,那么您需要做的就是告诉编译器您的实例属于Api
类型:
class ServiceClient {
// implement proxy magic here
}
let client = new ServiceClient() as any as Api;
let result = client.foo();
这应该可以解决问题,因为它创建了代理事物的类的实例,然后欺骗编译器认为这是Api
的实例。