Typegoose 如何将泛型类或模型作为函数参数传递

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

假设我定义了这两个模式:

import { prop, getModelForClass, type Ref, ReturnModelType } from '@typegoose/typegoose';

class User {
  @prop({ required: true, trim: true })
  public email!: string;

  @prop({ trim: true })
  public firstName?: string;

  @prop({ trim: true })
  public lastName?: string;

  @prop()
  public lastUpdate?: Date;

  // just for demo
  public static method1() {
    return true;
  }
}

export const UserModel = getModelForClass(User);


class Ticket {
  @prop({ required: true, ref: () => User })
  public user!: Ref<User>;

  @prop()
  public dateOpen?: Date;

  @prop({ trim: true })
  public message?: string;

  @prop()
  public lastUpdate?: Date;

  // just for demo
  public static method1() {
    return false;
  }
}

export const TicketModel = getModelForClass(Ticket);

我需要编写一个接受模型和类作为参数的通用函数,并操作一些数据。像这样的东西:

const genericFunction = <T>(updDocData: Partial<T>, dataClass: T): Partial<T> => {
  if (dataClass.method1 && typeof dataClass.method1 === 'function' && dataClass.method1() && dataClass.lastUpdate) {
    updDocData.lastUpdate = new Date();
  }

  return updDocData;
}

// demo use
let dataToUpdateForUser = genericFunction<User>({firstName: "updatedName"}, User);
let dataToUpdateForTicket = genericFunction<Ticket>({message: "updatedMessage"}, Ticket);

我收到大量打字稿错误:

  • 类型“T”上不存在属性“method1”
  • 类型“Partial”上不存在属性“lastUpdate”
  • “typeof User”类型的参数不可分配给“User”类型的参数。 “typeof User”类型中缺少属性“email”,但“User”类型中需要属性“email”。

我不知道如何将“User”或“Ticket”类(不是实例)传递给我的通用函数。我无法提前知道 lastUpdate 属性是否存在,也无法知道 method1 。这是我必须在函数内部执行的检查。

我尝试过一些类型,如 ReturnModelType 或 DocumentType,但没有成功。 我错过了什么?

typegoose
1个回答
0
投票

类型“T”上不存在属性“method1”
类型“Partial”上不存在属性“lastUpdate”

您必须限制

T
才能拥有这些属性,例如使用自定义界面(请参见下面的示例)。

“typeof User”类型的参数不可分配给“User”类型的参数。 “typeof User”类型中缺少属性“email”,但“User”类型中需要属性“email”。

Typescript 这里不直观,类的 type(在本例中为

User
)是 实例类型,而不是 static 类型,所以如果你这样做
const t: User = User
,你会得到一个编译错误,但是
const t: User = new User()
会起作用的。

有关更多信息,请阅读 typegoose 文档 值和类型之间的区别


我不完全确定你想用你的函数完成什么,因为它有一个逻辑问题:
您想要接收 typegoose class 并执行 static 方法(

method1
),然后检查 相同值上的
实例属性
(lastUpdate),但它不是实例。此外,您可能实际上不想在类上调用它,而是在模型上调用它(在本例中
UserModel
)。

由于这个问题,我尽力想出了一个更有可能的情况,如果以下代码不是您搜索的内容,请澄清您想要什么输入以及那里有哪些属性可用。

无论如何,这是代码:

// NodeJS: 22.2.0
// MongoDB: 5.0 (Docker)
// Typescript 5.3.3
import { DocumentType, Ref, getModelForClass, prop } from '@typegoose/typegoose'; // @typegoose/[email protected]
import * as mongoose from 'mongoose'; // [email protected]

interface Updateable {
  method1(): boolean;
  lastUpdate?: Date;
}

class User {
  @prop({ required: true, trim: true })
  public email!: string;

  @prop({ trim: true })
  public firstName?: string;

  @prop({ trim: true })
  public lastName?: string;

  @prop()
  public lastUpdate?: Date;

  public method1() {
    return true;
  }
}

export const UserModel = getModelForClass(User);

class Ticket {
  @prop({ required: true, ref: () => User })
  public user!: Ref<User>;

  @prop()
  public dateOpen?: Date;

  @prop({ trim: true })
  public message?: string;

  @prop()
  public lastUpdate?: Date;

  public method1() {
    return false;
  }
}

export const TicketModel = getModelForClass(Ticket);

interface MaybeLastUpdate {
  lastUpdate?: Updateable['lastUpdate'];
}

function genericFunction<T extends MaybeLastUpdate, D extends mongoose.Document & Updateable>(
  updDocData: T,
  dataDoc: D
): T & MaybeLastUpdate {
  if (dataDoc.method1 && typeof dataDoc.method1 === 'function' && dataDoc.method1() && dataDoc.lastUpdate) {
    updDocData.lastUpdate = new Date();
  }

  return updDocData;
}

const userDoc = new UserModel();
const ticketDoc = new TicketModel();

const dataToUpdateForUser = genericFunction<Partial<User>, DocumentType<User>>({ firstName: 'updatedName' }, userDoc);
const dataToUpdateForTicket = genericFunction<Partial<Ticket>, DocumentType<Ticket>>({ message: 'updatedMessage' }, ticketDoc);

console.log('dataToUpdateForUser', dataToUpdateForUser);
console.log('dataToUpdateForTicket', dataToUpdateForTicket);

(此代码也可以在 typegoose-testing 分支中找到)

注意:根据函数实际需要的内容,此代码可能会被更多地清理

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