mongoose 如何创建类型脚本自定义类型错误和默认类型?

kzmpq1sx  于 2023-06-23  发布在  Go
关注(0)|答案(1)|浏览(117)

bounty还有4天到期。此问题的答案有资格获得+50声望奖励。EcksDy希望引起更多注意这个问题:答案应该包括问题的解决方案,最好是解释类型系统的行为。

我尝试创建一个PojoDocument<T>泛型类型,以防止mongoose文档从DAL中泄漏。
我的目标是确保返回的对象不是mongoose Document,而是POJO(PojoDocument)。
我通过检查T永远不能有$locals属性来做到这一点,因为它在所有文档中都可以找到:

// If `T` has `$locals` property, then resolve the string as the type, which will clash with `T` and show as an error. 
// So when `$locals` property not found, `T` will be returned as the type. 
export type PojoDocument<T> = T & T extends { $locals?: never }
  ? T
  : 'Please convert the document to a POJO via `.toObject()` or .lean()`';

我的类型用法如下:

class A {
...
  async create(dto: CreateUserDto): Promise<PojoDocument<User>> {
    const result = await this.userModel.create(dto);
    return result.toObject();
    // ^ Type 'LeanDocument<User & Document<any, any, User>>' is not assignable to type '"Please convert the document to a POJO via `.toObject()` or .lean()`"'.
  }
}

LeanDocument<User & Document<any, any, User>>类型等于:

interface ResultToObjectType {
  __v?: any;
  _id?: any;
  name: string;
}

此外,当我检查create方法在使用它的地方返回的内容时,我得到了以下结果:

Promise<"Please convert the document to a POJO via `.toObject()` or .lean()`">

这意味着PojoDocument<T>默认为“else”条件,而不是为其提供的T
我尝试修改类型以包含__v_id,认为这就是它不认为该类型被$locals?: never扩展的原因,因为这些属性在T上不存在,但它没有改变任何东西:

export type PojoDocument<T> = T extends { $locals?: never; __v?: any; _id?: any }
  ? T
  : 'Please convert the document to a POJO via `.toObject()` or .lean()`';

有什么想法可以实现这种检查?

编辑#1

我加了一个小型的游戏场。

q3aa0525

q3aa05251#

问题实际上是UsersDal.create,其中返回类型为:

Promise<PojoDocument<User>>

User只有name,不符合PojoDocument的要求,返回字符串错误:

// type Test = "Please convert the document to a POJO via `.toObject()` or .lean()`"
type Test = PojoDocument<User>

然而,pojoResult确实遵守PojoDocument的条件,显然,它不是函数期望返回的字符串。
总结问题:
您的create期望返回一个文本字符串的promise,而不是promise对象。
我不熟悉mongoose,但我可以建议将create的返回类型更改为:

Promise<PojoDocument<LeanDocument<User & Document<any, any>>>>

完整代码:

class UsersDal {
  constructor(private userModel: Model<User>) {}

  async create(createDto: UserDto): Promise<PojoDocument<LeanDocument<User & Document<any, any>>>> {
    const result = await this.userModel.create(createDto);

    const pojoResult = result.toObject();
    return pojoResult; // no error
  }
}

class UsersService {
  constructor(private usersDal: UsersDal) {}

  async create(createDto: UserDto): Promise<User> {
    const result = await this.usersDal.create(createDto);
    return result; // no error
  }
}

Playground

相关问题