扩展在其构造函数中显式返回对象的 JavaScript ES6+ 类

问题描述 投票:0回答:1

我在扩展从构造函数返回对象的 Javascript ES6+ 类时遇到问题。

举个例子:

class Base {
  constructor() {
    return {name: "base"}
  }
}

class Extension extends Base {
  constructor() {
    super()
  }

  saySomething() {
    console.log("What do you want me to say?")
  }
}

创建

Extension
类的新实例并调用
saySomething
失败并出现错误,因为无论出于何种原因,我认为这与基类在其构造函数中返回值有关,方法
saySomething
似乎不存在(事实上,除了属于基类的内容之外,什么也没有)在
Extension
类原型上。

导致这个基本问题的主要问题是我试图创建一个扩展的

PrismaClient
如此处所示,在 NestJS 中使用客户端扩展,这种特定方式会导致
PrismaService
类上的其他方法不存在在原型链上。


function PrismaExtended() {
  type Params = ConstructorParameters<typeof PrismaClient<Prisma.PrismaClientOptions, Prisma.LogLevel>>;
  const client = (...args: Params) =>
    new PrismaClient<Prisma.PrismaClientOptions, Prisma.LogLevel>(...args).$extends({
      result: {
        $allModels: {
          toJSON: {
            compute(data: BaseEntity) {
              return <T extends typeof data = typeof data>() => {
                return Object.assign({}, data, {
                  sn: typeof data.sn === 'bigint' ? data.sn.toString() : data.sn,
                }) as unknown as Omit<T, 'sn'> & { sn: string };
              };
            },
          },
        },
      },
    });

  class PrismaExtended {
    constructor(...args: Params) {
      return client(...args);
    }
  }

  // Object.setPrototypeOf(PrismaExtended, PrismaClient.prototype);
  return PrismaExtended as new (...args: Params) => ReturnType<typeof client>;
}

@Injectable()
export class PrismaService extends PrismaExtended() implements OnModuleInit, OnModuleDestroy {
  private retries: number = 0;
  constructor(
    private readonly logger: AppLogger,
    configService: ConfigService,
  ) {
    super({
      log: pickFrom(configService, 'app.status') !== NodeEnv.PROD ? ['query'] : undefined,
      transactionOptions: { timeout: 60_000 },
    });
  }

  /**
   * Check if an error is as a result of a precodition necessary to run an
   * operation not being matched.
   *
   * @param e The error to check
   * @returns boolean
   */
  isUnmatchedPrecondition(e: unknown): e is PrismaClientKnownRequestError {
    return e instanceof PrismaClientKnownRequestError && e.code === PrismaErrorCode.UNMATCHED_PRECONDITION;
  }
}

这里的方法,

isUnmatchedPrecondition
,以及添加的任何其他方法在运行时都不存在。

javascript nestjs prisma es6-class
1个回答
0
投票

我现在可以使用

Proxy
让它发挥作用。

使用双代理,一种用于在

PrismaService
上使用 new 关键字时拦截对象构造,并且因为理想情况下应该从
Proxy
继承的
PrismaClient
构造的对象没有“”的方法或属性假定的基类”(因为没有发生
PrismaClient
的继承),它已经在子类构造函数上下文之外构造,我必须保留“假定的基类”的引用并维护对构造的代理子类,这样当在子类实例上访问任何方法或属性并且找不到它时,它会被重定向到假定的基类,我在调用
getClient
的最外层代理中保留对该基类实例的引用。


function PrismaExtended() {
  type Params = ConstructorParameters<typeof PrismaClient<Prisma.PrismaClientOptions, Prisma.LogLevel>>;
  const getClient = (...args: Params) => {
    return new PrismaClient<Prisma.PrismaClientOptions, Prisma.LogLevel>(...args).$extends({
      result: {
        $allModels: {
          toJSON: {
            compute(data: BaseEntity) {
              return <T extends typeof data = typeof data>() => {
                return Object.assign({}, data, {
                  sn: typeof data.sn === 'bigint' ? data.sn.toString() : data.sn,
                }) as unknown as Omit<T, 'sn'> & { sn: string };
              };
            },
          },
        },
      },
    });
  };

  return new Proxy(class {}, {
    construct(target, args, newTarget) {
      const client = getClient(...args);
      const constructed = Reflect.construct(target, args, newTarget);

      return new Proxy(constructed, {
        get(target, key) {
          if (key in target) return target[key];
          return client[key];
        },
      });
    },
  }) as unknown as new (...args: Params) => ReturnType<typeof getClient>;
}

目前,这似乎工作正常,到目前为止我还没有记录任何“捕获”。但是,嘿,如果你确实注意到我遗漏了一些东西,或者关于这个解决方案的任何陷阱,请告诉我。

感谢所有为帮助我做出贡献的人。

© www.soinside.com 2019 - 2024. All rights reserved.