如何正确定义包装第 3 方 class 的代理类型?

How do I correctly define the type for a proxy wrapping a 3rd party class?

我通过将 Firestore 的查询 class 包装到代理中来编写包装器。我的代理基本上做了两件事:

  1. 如果您调用查询 class 中存在的函数,我的代理会将您的函数调用转发给查询 class。
    • 然后如果查询 class return 是其自身的另一个实例(例如,当您调用 .where() 时),我的代理不会 return 那个查询实例,但是相反,我的代理只是将该 Query 实例包装在另一个代理中。
    • 然而,如果 return 类型不是 Query 的另一个实例(例如,当您调用 .onSnapshot() 时),则结果会透明地返回给方法的调用者,而不会发生任何包装.
  2. 我的代理添加了一些我自己喜欢的方法。

我第一次尝试写类型定义如下:

interface MyInterface { /* this contains my own methods */ }
type Store = MyInterface & FirebaseFirestore.Query

这仅在我在我的商店上调用查询方法时打字稿理解该方法可用的意义上起作用。但是当然,这并没有让 typescript 清楚地知道所有查询方法的 return 类型都将被包装到另一个 Store 类型中。我如何将其传达给打字稿?

我想你需要这样的东西:

interface Snapshot {}

interface Helper {}

interface Query {
  where(a: number): Query;
  onSnapshot(): Snapshot;
}

type ProxyWrapper<T> = {
  [K in keyof T]: T[K] extends (...a: any) => T
    ? (...a: Parameters<T[K]>) => ProxyWrapper<T>
    : T[K]
};

interface ProxyExt {
  newMethod(): Helper;
}

let proxy: ProxyWrapper<Query> & ProxyExt;

proxy.onSnapshot(); // Snapshot
proxy.where(2); // Proxy<Query>
proxy.newMethod(); // Helper