微信输入打字框变得很小
Have you ever struggled to get the TypeScript description of your data to match the Mongoose description of your data? Have you been surprised when your code editor starts giving you typing errors for Mongoose functions that you know are there? If so, here is an approach to working with both TypeScript and Mongoose that works reasonably well.
您是否曾经努力使数据的TypeScript描述与数据的Mongoose描述相匹配? 当您的代码编辑器开始为您知道的 Mongoose函数输入错误时,您是否感到惊讶? 如果是这样,这是一种同时使用TypeScript和Mongoose的方法,效果很好。
This guide will look at typing the ‘Animal’ example prevalent in the Mongoose documentation. In order to use Mongoose with TypeScript, you should be sure to include the @types/mongoose package from DefinitelyTyped in your application.
本指南将研究在Mongoose文档中常见的“动物”示例。 为了将Mongoose与TypeScript一起使用,应确保在应用程序中包含DefinitelyTyped中的@ types / mongoose包。
模式 (Schemas)
A schema is a description of your data that mongoose uses to give some structure to your documents. To describe a schema, Mongoose uses its own SchemaTypes. SchemaTypes can appear quite similar to the way data is typed in TypeScript, but there are differences in terms of both syntax and the actual data shape. When you define a Mongoose schema, Mongoose will append additional functionality to any documents created with that schema. For example, if you define a schema that contains an array, Mongoose will attach .pull()
and .id()
methods to the document. The challenge is to define your TypeScript types to accurately reflect the mongoose output. If you do not, TypeScript will complain when you try to use the .pull()
method. Let’s start with a schema definition for animals (taken from the Mongoose documentation)
模式是对猫鼬用来为文档提供某种结构的数据的描述。 为了描述一个模式,Mongoose使用了自己的SchemaTypes 。 SchemaTypes看起来与TypeScript中的数据键入方式非常相似,但是语法和实际数据形状方面有所不同。 当您定义Mongoose模式时,Mongoose会将附加功能附加到使用该模式创建的任何文档中。 例如,如果您定义一个包含数组的架构,Mongoose会将.pull()
和.id()
方法附加到文档中。 挑战在于定义您的TypeScript类型以准确反映猫鼬的输出。 如果不这样做,当您尝试使用.pull()
方法时,TypeScript会抱怨。 让我们从动物的模式定义开始(摘自Mongoose文档)
数据,文件,模型 (Data, Documents, Models)
When creating TypeScript typings for Mongoose, it is helpful to to consider three cases or levels: Data, Documents, and Models.
在为Mongoose创建TypeScript类型时,考虑以下三种情况或级别是有帮助的:数据,文档和模型。
In this context, data is what you want to persist to the database in the form of a Document. In mongoose terms, a document is a particular instance of a model. A model is compiled from your schema definition and used to interact with the database. You can think of a model as the as the mechanism by which your data gets turned into documents and vice-versa. However, in order for our typings to work nicely, we actually define the data first, then define the documents, and finally define the models.
在这种情况下, 数据就是要以文档形式保存到数据库的数据。 用猫鼬的术语来说, 文档是模型的特定实例。 根据您的架构定义编译模型,并将其用于与数据库进行交互。 您可以将模型视为将数据转化为文档的机制,反之亦然。 但是,为了使我们的键入工作正常,我们实际上首先定义数据,然后定义文档,最后定义模型。
数据 (Data)
It is good to think about the actual data you want to store in the database in terms of Plain Old JavaScript Objects (or “POJOs”) and type it accordingly. They shouldn’t contain any methods, only data.
最好用Plain Old JavaScript Objects(或“ POJO ”)来考虑要存储在数据库中的实际数据,并相应地键入它。 它们不应包含任何方法,而只能包含数据。
So far, this looks almost exactly like the schema, and that’s a good thing. We don’t include any methods, meaning that we could safely re-use this interface in the front-end if we wanted to.
到目前为止,这看起来几乎与模式完全一样,这是一件好事。 我们不包含任何方法,这意味着我们可以在前端安全地重用此接口。
Virtuals
虚拟机
Virtual attributes are bits of data that are not persisted to the database, but are composed on the fly (rather like a getter) . In our example we might have a virtual nationalType
that combined the type and country where the animal is located. First, lets update our schema:
虚属性是不是持久存储在数据库中的数据位,而是动态组成的(就像吸气剂一样 )。 在我们的示例中,我们可能有一个虚拟的nationalType
,将动物的类型和所在国家/地区结合在一起。 首先,让我们更新架构:
Second, lets define the virtual:
其次,让我们定义虚拟:
Whether you place these on the POJO or not depends on your schema options. If you define your schema to always include virtuals (with {virtuals:true}
) they should go on the POJO since you can expect them to be present even after they have been sent to the front-end. If not, they should go on the document level. For example, if our animal schema looked like this:
是否将它们放在POJO上取决于您的模式选项。 如果您将架构定义为始终包含虚拟(使用{virtuals:true}
),则它们应继续进行POJO,因为您可以期望它们已经存在,即使它们已经发送到前端。 如果没有,他们应该进入文档级别。 例如,如果我们的动物模式如下所示:
Then, we would expect the virtual to be there on any document we retrieved from the database, so we should type it as an optional property. Our interface now looks like this:
然后,我们希望虚拟变量存在于我们从数据库检索到的任何文档中,因此我们应将其键入为可选属性。 现在,我们的界面如下所示:
文件资料 (Documents)
A Document is an instance of a Mongoose model. It has the same data as our POJO object, but it also has methods. Some of these methods are provided by Mongoose automatically, but we can also define them ourselves in the schema.
文档是猫鼬模型的一个实例。 它与我们的POJO对象具有相同的数据,但也具有方法。 其中一些方法是Mongoose自动提供的,但是我们也可以在模式中自己定义它们。
Methods
方法
The mongoose documentation gives the example of a findSimilarTypes()
method that lives on a document. We would define the function and add it to the schema like this:
猫鼬文档给出了文档中存在的findSimilarTypes()
方法的示例。 我们将定义函数并将其添加到架构中,如下所示:
Note that in our function definition we use TypeScript’s fake this
to make it aware of the typing within the function.
请注意,在函数定义中,我们使用TypeScript的fake this
来使其了解函数内的键入。
Because the findSimilarTypes()
function only works on the back-end (where the application has access to the database connection) we should not include it in our IAnimal interface.
因为findSimilarTypes()
函数仅在后端(应用程序可以访问数据库连接)上起作用,所以我们不应在IAnimal接口中包括它。
On the back-end, however, in order for TypeScript to know about this method and the properties built in to all Mongoose documents, we would need to define a new interface, IAnimalDocument, extending both the Document type provided by mongoose and our IAnimal interface:
但是,在后端,为了让TypeScript知道此方法和所有Mongoose文档中内置的属性,我们需要定义一个新接口IAnimalDocument,以扩展mongoose提供的Document类型和我们的IAnimal接口:
This helps us to keep the typing of our back-end methods separate from the typing of our data.
这有助于我们将后端方法的类型与数据的类型区分开。
楷模 (Models)
Models are compiled from schema definitions and are the normal way that you interact with the database when using mongoose.
模型是根据模式定义编译的,是使用猫鼬时与数据库进行交互的常规方式。
Statics
静力学
You can add functions to models. To distinguish them from document methods, these are called statics.
您可以向模型添加功能。 为了将它们与文档方法区分开来,这些称为静态方法。
We can define a static method, findByName()
, on our animal schema (again using the fake this
) like so:
我们可以在动物模式上定义一个静态方法findByName()
(再次使用false this
),如下所示:
To give the model the correct type, we define the its interface like this:
为了给模型正确的类型,我们定义它的接口,如下所示:
Now we will be able to call our findByName()
function on our animal model, but we will get a typing error if we mistakenly try to call it on a document.
现在,我们将能够在动物模型上调用findByName()
函数,但是如果我们错误地尝试在文档上调用它,则会出现键入错误。
总结:导出类型化模型 (Wrapping up: Exporting the typed model)
Finally, we can export our Animal model, passing in the document, model typings,and schema like so:
最后,我们可以导出动物模型,传入文档,模型类型和模式,如下所示:
One remaining potential issue comes from the populate feature. This feature allows a field to reference data in another collection, and pull it into the document. Lets say our animal had an owner
field, that referenced a document in the owners collection. In this case, the type of the owner would be either an ObjectId
or an Owner
. One way of dealing with this is to use the autopopulate plugin in combination with type guards. Another would be to create static methods that return populated versions of the document, this would mean creating another interface that extends IAnimalDocument. Of course, there is nothing saying that you have to use population, but it is often cleaner to do so.
剩余的潜在问题来自填充功能。 此功能允许字段引用另一个集合中的数据,并将其拉入文档。 假设我们的动物有一个owner
字段,该字段引用了所有者集合中的文档。 在这种情况下,所有者的类型将是ObjectId
或 Owner
。 解决此问题的一种方法是将autopopulate插件与类型卫士结合使用。 另一个方法是创建返回文档填充版本的静态方法,这意味着创建另一个扩展IAnimalDocument的接口。 当然,没有什么可以说必须使用人口,但是这样做通常更清洁。
Breaking the typings down into smaller parts can seem like a lot of extra work, but it pays off in having accurate typings which will mean more reliable code in the future.
将类型分解为较小的部分可能看起来像很多额外的工作,但是要获得准确的类型却有回报,这将意味着将来的代码更加可靠。
翻译自: https://medium.com/@_telega/make-typescript-and-mongoose-play-nicely-together-3d3c94a91e34
微信输入打字框变得很小