NodeJS JavaScript代码到TypeScript的转换

jmo0nnb3  于 2023-08-04  发布在  Node.js
关注(0)|答案(1)|浏览(120)

我正在尝试扩展mongoose查询函数,以便能够将缓存函数附加到mongoose查询。我已经完成了JavaScript的实现,但是当我尝试用typescript实现它时,会遇到不同的错误
JavaScript代码是:

const mongoose = require('mongoose');
const exec = mongoose.Query.prototype.exec;
const redisClient = require('./RedisClient');

mongoose.Query.prototype.cache = function (options = {}) {
  this.useCache = true;
  this.hashKey = JSON.stringify(options.key || '');
  return this;
}

mongoose.Query.prototype.exec = async function () {
  if (!this.useCache) {
    return exec.apply(this, arguments);
  }

  const key = JSON.stringify(Object.assign({}, this.getFilter(), {
    collection: this.mongooseCollection.name
  }));

  const cachedValue = await redisClient.getHCache(this.hashKey, key);

  if (cachedValue) {
    const doc = JSON.parse(cachedValue);
    return Array.isArray(doc)
      ? doc.map(d => new this.model(d))
      : new this.model(doc);
  }

  const result = await exec.apply(this, arguments);
  await redisClient.setHCache(this.hashKey, key, JSON.stringify(result));

  return result;
}

字符串
我的typescript实现是

import mongoose, { Query } from 'mongoose';
import RedisClient  from './redisClient';

declare module 'mongoose' {
  interface Query<T> {
    useCache?: boolean;
    hashKey?: string;
    cache(options?: { key?: unknown }): Query<T>;
  }
}

const exec = Query.prototype.exec;

Query.prototype.cache = function (options = {}): Query<any> {
  this.useCache = true;
  this.hashKey = JSON.stringify(options.key || '');
  return this;
};

Query.prototype.exec = async function (): Promise<any> {
  if (!this.useCache) {
    return exec.apply(this, arguments);
  }

  const key = JSON.stringify(Object.assign({}, this.getFilter(), {
    collection: this.mongooseCollection.name,
  }));

  const cachedValue = await RedisClient.getHCache(this.hashKey, key);

  if (cachedValue) {
    const doc = JSON.parse(cachedValue);
    return Array.isArray(doc)
      ? doc.map((d: any) => new this.model(d))
      : new this.model(doc);
  }

  const result = await exec.apply(this, arguments);
  await RedisClient.setHCache(this.hashKey, key, JSON.stringify(result));

  return result;
};


我得到的错误是;
“Query”的所有声明必须具有相同的类型参数。
“IArguments”类型的参数不能分配给“[]”类型的参数
类型“Query<any,any,any,any,any,any>”上不存在属性“mongooseCollection”。你是说mongooseoptions吗?
请协助

mklgxw1f

mklgxw1f1#

以下是正确的方法,同时也解释了更改的原因-

declare module "mongoose" {
    // For the declaration merging to work, any existing declaration from the module needs to be declared exactly the same
    // which is why `interface Query<T>` doesn't work and you have to make the declaration identical to declaration from the library itself
    // Query<T> {
    interface Query<ResultType, DocType, THelpers = {}, RawDocType = DocType, QueryOp = "find"> {
        useCache?: boolean;
        hashKey?: string;
        cache(options?: { key?: unknown }): Query<ResultType, DocType, THelpers, RawDocType, QueryOp>;
    }
}

const exec = Query.prototype.exec;

Query.prototype.cache = function (options = {}) {
    this.useCache = true;
    this.hashKey = JSON.stringify(options.key || '');
    return this;
}

Query.prototype.exec = async function (): Promise<any> {
    if (!this.useCache) {
        // No need to pass `arguments` as the exec doesn't take any arguments per function signature
        // The type of arguments is IArguments in typescript by default, and when there's no arguments,
        // the type inferred is [], i.e., an empty array hence the error: Argument of type 'IArguments' is not assignable to parameter of type '[]'
        // return exec.apply(this, arguments);
        return exec.apply(this);
    }

    const key = JSON.stringify(Object.assign({}, this.getFilter(), {
        // this.mongooseCollection is used internally by the Query [1], and although it's added in the redis
        // cache setup guide (which is quite old, and was written 4 years ago [2], and the official typescript bindings came later on [3][4]), it's not available for use through API
        // access collection from the model itself.
        // [1] https://github.com/Automattic/mongoose/blob/865887862721689aa1fa6657af2d9b17e001a82e/lib/query.js#L111
        // [2] https://github.com/Automattic/mongoose/blame/865887862721689aa1fa6657af2d9b17e001a82e/examples/redis-todo/services/cache.js#L22
        // [3] https://mongoosejs.com/docs/typescript.html#typescript-support
        // [4] https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md#5110--2020-11-30
        // collection: this.mongooseCollection.name,
        collection: this.model.collection.name,
    }));

    const cachedValue = await RedisClient.getHCache(this.hashKey, key);

    if (cachedValue) {
        const doc = JSON.parse(cachedValue);
        return Array.isArray(doc)
            ? doc.map((d: any) => new this.model(d))
            : new this.model(doc);
    }
    // No need to pass `arguments` as the exec doesn't take any arguments per function signature
    // The type of arguments is IArguments in typescript by default, and when there's no arguments,
    // the type inferred is [], i.e., an empty array hence the error: Argument of type 'IArguments' is not assignable to parameter of type '[]'
    // const result = await exec.apply(this, arguments);
    const result = await exec.apply(this);
    await RedisClient.setHCache(this.hashKey, key, JSON.stringify(result));

    return result;
};

字符串
这里有一个链接到操场。

相关问题