Skip to content

最终方案

https://docs.qq.com/aio/DUU5tSnJsY0NmZW1T

ts
// 类型定义 --------------------------------------------------------
// 深度只读包装
type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends (...args: any[]) => any
    ? (...args: Parameters<T[K]>) => ReturnType<T[K]>
    : T[K] extends object
      ? DeepReadonly<T[K]>
      : T[K];
};

type Methods<T> = {
  [K in keyof T as T[K] extends (...args: any[]) => any ? K : never]: T[K];
};

// 只返回方法
type MethodsOnly<T> = Pick<
  T,
  {
    [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;
  }[keyof T]
>;

type ServiceType<T, S> = DeepReadonly<Methods<T> & S>;

// Proxy处理器 ----------------------------------------------------
const createProxyHandler = (rawInstance: any) => ({
  get(target: any, prop: string | symbol) {
    // 优先返回selector属性
    if (prop in target.__selector) {
      return target.__selector[prop];
    }

    // 处理原型方法
    const value = Reflect.get(target.__raw, prop);
    if (typeof value === 'function') {
      return (...args: any[]) => value.apply(rawInstance, args);
    }
    return value;
  },

  set() {
    return false; // 完全禁止写操作
  },
});

// 实现函数 --------------------------------------------------------
function useService<T extends new (...args: any[]) => any, S extends object>(
  ClassName: T,
  selector?: (instance: InstanceType<T>) => S
): ServiceType<InstanceType<T>, S> {
  const rawInstance = new ClassName();
  const selected = selector ? selector(rawInstance) : ({} as S);

  // 创建代理对象
  const proxy = new Proxy(
    {
      __raw: rawInstance, // 原始实例引用
      __selector: selected, // selector结果
    },
    createProxyHandler(rawInstance)
  );

  return proxy as unknown as ServiceType<InstanceType<T>, S>;
}