Mongoose如何强制执行LeanDocument类型?

huangapple go评论82阅读模式
英文:

Mongoose, how to enforce LeanDocument type?

问题

以下是您要翻译的内容:

在我们的代码库中,我们一直在使用 T.lean()T.toObject(),我们的返回类型将是 LeanDocument<T>。Mongoose 7 不再导出 LeanDocument,现有的迁移指南建议使用以下设置:

  1. // 改用这个,不再使用 `extends Document`
  2. interface ITest {
  3. name?: string;
  4. }
  5. const Test = model<ITest>('Test', schema);
  6. // 如果需要访问已填充的文档类型,请使用以下代码
  7. type TestDocument = ReturnType<(typeof Test)['hydrate']>

但这会给我一个 HydratedDocument,我可以通过 HydratedDocument<T> 获取它,这不是我想要的,因为它包含了所有文档方法。作为替代,我可以只使用 T 作为返回类型,但然后任何 Document<T> 都与 T 匹配。

我希望强制确保结果是一个普通的 JavaScript 对象(POJO),以防止文档从我们的数据访问层(DAL)泄漏。

如何在 TypeScript 和 Mongoose 类型中实现这一点?

英文:

In our codebase we've been using T.lean() or T.toObject() and our return types would be LeanDocument<T>. Mongoose 7 no longer exports LeanDocument, and the existing migration guide suggests using the following setup:

  1. // Do this instead, no `extends Document`
  2. interface ITest {
  3. name?: string;
  4. }
  5. const Test = model<ITest>('Test', schema);
  6. // If you need to access the hydrated document type, use the following code
  7. type TestDocument = ReturnType<(typeof Test)['hydrate']>;

But this gives me HydratedDocument that I can get by HydratedDocument<T>, which is not what I want since it has all the document methods on it.
As an alternative I can use just T as my return type, but then any Document<T> is matching T.

I'd like to enforce that the result is a POJO, to prevent documents leaking from our DAL.

How can I achieve that with typescript and mongoose types?

答案1

得分: 1

以下是要翻译的内容:

在mongoose存储库中提出了类似的问题后,我已经采用了以下方法:

  1. // utils.ts
  2. export type LeanDocument<T> = T & { $locals?: never };

因此,在以下情况下,typescript将提醒我不能返回文档:

  1. async function getById(id: string): Promise<LeanDocument<User>> {
  2. const user = await UserModel.findById(id);
  3. return user;
  4. // ^ 属性'$locals'的类型不兼容。
  5. }

我认为可以通过制定更清晰的类型错误来进一步改进,该错误将陈述类似于“类型错误...“您忘记将其转换为精简文档”。正如我之前在库中看到的那样。但是我还没有找到如何做到这一点 Mongoose如何强制执行LeanDocument类型?

编辑

一些typescript魔法:

  1. export type LeanDocument<T> = T & T extends { $locals: never }
  2. ? T
  3. : '请通过`.toObject()`将文档转换为普通对象';

将导致以下错误:

  1. async function getById(id: string): Promise<LeanDocument<User>> {
  2. const user = await UserModel.findById(id);
  3. return user;
  4. // ^ 类型'Document<unknown, any, User> & Omit<User & { _id: ObjectId; }, never>'不可分配给类型'"请通过`.toObject()`将文档转换为普通对象"。ts(2322)
  5. }

编辑 2

使用条件类型的类型错误未按预期工作,我尝试在此问题中解决它。不幸的是,有效的解决方案需要包装函数和断言。

英文:

Asking a similar question over at the mongoose repo, I've settled on the following approach:

  1. // utils.ts
  2. export type LeanDocument&lt;T&gt; = T &amp; { $locals?: never };

So in the following case, typescript will remind me that I cannot return document:

  1. async function getById(id: string): Promise&lt;LeanDocument&lt;User&gt;&gt; {
  2. const user = await UserModel.findById(id);
  3. return user;
  4. // ^ Types of property &#39;$locals&#39; are incompatible.
  5. }

I think this can be further improved by making a clearer type error that will state something along the lines of Type error ... &quot;You&#39;ve forgot to convert to a lean document&quot;., as I've seen that in libraries before.
<strike>But I haven't found how to do that yet :)</strike>

Edit

Some typescript magic:

  1. export type LeanDocument&lt;T&gt; = T &amp; T extends { $locals: never }
  2. ? T
  3. : &#39;Please convert the document to a plain object via `.toObject()`&#39;;

Will result in the following error:

  1. async function getById(id: string): Promise&lt;LeanDocument&lt;User&gt;&gt; {
  2. const user = await UserModel.findById(id);
  3. return user;
  4. // ^ Type &#39;Document&lt;unknown, any, User&gt; &amp; Omit&lt;User &amp; { _id: ObjectId; }, never&gt;&#39;
  5. // is not assignable to type
  6. // &#39;&quot;Please convert the document to a plain object via `.toObject()`&quot;&#39;.ts(2322)
  7. }

Edit 2

The type error using conditional types did not work as expected and I've tried to solve it in this question. Unfortunately the working solution required a wrapping function and assertion.

huangapple
  • 本文由 发表于 2023年5月11日 19:49:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76227334.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定