Docs HomeNode.js

TypeScript

Overview概述

In this guide, you can learn about the TypeScript features and limitations of the MongoDB Node.js driver. 在本指南中,您可以了解MongoDB Node.js驱动程序的TypeScript功能和限制。TypeScript is a strongly typed programming language that compiles to JavaScript.TypeScript是一种可编译为JavaScript的强类型编程语言。

The TypeScript compiler offers type checking in real time. TypeScript编译器提供实时的类型检查。Code editors that support TypeScript can provide autocomplete suggestions, display documentation inline, and identify type-related errors.支持TypeScript的代码编辑器可以提供自动完成建议、内联显示文档以及识别与类型相关的错误。

All TypeScript features of the driver are optional. 驱动程序的所有TypeScript功能都是可选的。All valid JavaScript code written with the driver is also valid TypeScript code.所有使用驱动程序编写的有效JavaScript代码也是有效的TypeScript代码。

For more information, see the TypeScript website.有关更多信息,请参阅TypeScript网站

Features功能

If you use TypeScript, you can specify a type for some classes in the driver. 如果使用TypeScript,则可以为驱动程序中的某些类指定类型。All classes that accept a type parameter in the driver have the default type Document. 所有在驱动程序中接受类型参数的类都具有默认类型DocumentThe Document interface has the following definition:Document接口具有以下定义:

interface Document {
[key: string]: any;
}

All object types extend the Document interface.所有对象类型都扩展了Document接口。

For more information on object types, see the TypeScript handbook.有关对象类型的更多信息,请参阅TypeScript手册

Type Parameters that Extend Document扩展文档的类型参数

The following classes accept all types that extend the Document interface:以下类接受扩展Document接口的所有类型:

You can pass a type parameter that extends the Document interface like this:您可以传递一个扩展Document接口的类型参数,如下所示:

interface Pet {
name: string;
age: number;
}

const database = client.db("<your database>");
const collection = database.collection<Pet>("<your collection>");
Important

Keys Not in Type Parameter Receive any Type不在类型参数中的键接收任何类型

Keys not listed in your specified type parameter receive the any type. 指定类型参数中未列出的键将接收any类型。The following code snippet demonstrates this behavior:以下代码片段演示了这种行为:

interface User {
email: string;
}

const database = client.db("<your database>");
const myColl = db.collection<User>("<your collection>");
myColl.find({ age: "Accepts any type!" });

Type Parameters of Any Type任何类型的类型参数

The following classes accept all type parameters:以下类接受所有类型参数:

You can find a code snippet that shows how to specify a type for the FindCursor class in the Find Multiple Documents Usage Example.您可以在查找多个文档用法示例中找到一个代码片段,该代码片段显示如何为FindCursor类指定类型。

Type Safety and Dot Notation类型安全和点符号

Starting in version 5.0, by default, the Node.js driver does not provide type safety for operations that search on fields expressed in dot notation. 默认情况下,从版本5.0开始,Node.js驱动程序不会为搜索以句点表示的字段的操作提供类型安全性。Dot notation is a syntax you can use to navigate nested JSON objects. When you construct a filter to pass to a query, the driver will not raise a type error even if you specify an incorrectly typed value for a field expressed in dot notation.点表示法是一种可以用于导航嵌套JSON对象的语法。当您构造要传递给查询的筛选器时,即使您为以句点表示的字段指定了类型不正确的值,驱动程序也不会引发类型错误。

The following code snippet defines the ClassificationPet interface, which includes a classification field that enables you to specify the genus and color of dogs and cats:以下代码片段定义了ClassificationPet界面,其中包括一个classification字段,用于指定狗和猫的属和颜色:

interface ClassificationPet {
name: string;
age: number;
classification: { genus: "Canis" | "Felis"; color: string };
}

The driver does not raise a type error for the following code sample, even though the value of classification.color is a boolean instead of a string:驱动程序不会引发以下代码示例的类型错误,即使classification.color的值是布尔值而不是字符串:

await myColl.findOneAndDelete({ "classification.color": false });

You can enable type-checking by constructing filters as StrictFilter or StrictUpdateFilter types.您可以通过将筛选器构造为StrictFilterStrictUpdateFilter类型来启用类型检查。

Warning

The StrictFilter and StrictUpdateFilter types are experimental and may show type errors in valid queries where there should be none.StrictFilterStrictUpdateFilter类型是实验性的,可能会在有效查询中显示类型错误,而这些查询不应该有类型错误。

In the following code sample, the filter is assigned a StrictFilter type. 在下面的代码示例中,为筛选器分配了StrictFilter类型。Given this filter type, the Node.js driver reports a type error because the value of classification.color is a boolean instead of a string.给定这个筛选器类型,Node.js驱动程序会报告一个类型错误,因为classification.color的值是布尔值而不是字符串。

const filterPredicate: StrictFilter<ClassificationPet> = { "classification.color": false };
await myColl.findOneAndDelete(filterPredicate);

The following example assigns a StrictUpdateFilter type to an update filter. 以下示例将StrictUpdateFilter类型分配给更新筛选器。The Node.js driver reports a type error because the value of classification.color is a boolean instead of a string.Node.js驱动程序报告了一个类型错误,因为classification.color的值是布尔值而不是字符串。

const updateFilter: StrictUpdateFilter<ClassificationPet> = { $set: { "classification.color": false } }
await pets.updateOne({}, updateFilter);

Referencing Keys that Incorporate Variables引用包含变量的键

If you need to query a collection or perform another operation with a key that incorporates variables, you must use an as const assertion when specifying the key. 如果需要查询集合或使用包含变量的键执行其他操作,则在指定键时必须使用as const断言。This mechanism allows your code to compile successfully as long as the input types are correct.只要输入类型正确,这种机制就允许代码成功编译。

The following code snippet defines the ClassificationPet interface and the Mealtime interface. 以下代码片段定义ClassificationPet接口和Mealtime接口。ClassificationPet includes a mealtimes field that contains an array of Mealtime interfaces, each of which includes a time field:ClassificationPet包括一个mealtimes字段,该字段包含一组mealtimes接口,每个接口都包括一个time字段:

interface ClassificationPet {
name: string;
mealtimes: Mealtime[];
}

interface Mealtime{
time: string;
amount: number;
}

The following code snippet performs a find-and-update operation on a collection of ClassificationPet documents. 以下代码片段对ClassificationPet文档的集合执行查找和更新操作。The operation updates the nested time field of the Mealtime instance at index 1. 该操作将更新索引1Mealtime实例的嵌套time字段。The index position is specified by the variable mealCounter:索引位置由变量mealCounter指定:

const mealCounter = 1;

await myColl.findOneAndUpdate(
{ name: "Lassie" },
{ $set: { [`mealtimes.${mealCounter}.time` as const]: '4:00 PM' } },
);

To learn more about dot notation, see Dot Notation in the MongoDB manual.要了解更多关于点符号的信息,请参阅MongoDB手册中的点符号

To learn more about the limitations of dot notation in the Node.js driver, see the Recursive Types and Dot Notation section.要了解更多关于Node.js驱动程序中点符号的限制,请参阅递归类型和点符号部分。

Working with the _id Field使用_id字段

MongoDB does not recommend specifying the _id as a part of your model. MongoDB不建议将_id指定为模型的一部分。Omitting the _id field makes the model more generic and reusable and more accurately models the data important to an application. 省略_id字段可以使模型更加通用和可重用,并更准确地对应用程序重要的数据进行建模。The Node driver’s TypeScript integration takes care of adding the _id field to the return types for relevant methods.Node驱动程序的TypeScript集成负责将_id字段添加到相关方法的返回类型中。

If you need to work with the _id field in your models, see the below sections for information on write and read operations.如果您需要在模型中使用_id字段,请参阅以下部分以获取有关写和读操作的信息。

Insert Operations and the _id Field插入操作和_id字段

How you specify the _id field in type parameters passed to your Collection instance affects the behavior of insert operations. 在传递给Collection实例的类型参数中指定_id字段的方式会影响插入操作的行为。The following table describes how different _id field specifications affect insert operations:下表描述了不同的_id字段规范如何影响插入操作:

_id field typeExample Type示例类型Required on insert插入时需要Behavior on insert插入时的行为
Unspecified未指定Not applicable不适用NoThe driver creates an ObjectId value for each inserted document.驱动程序为每个插入的文档创建一个ObjectId值。
Specified指定{ _id: number };YesIf you do not specify a value for the _id field in an insert operation, the driver raises an error.如果在插入操作中没有为_id字段指定值,则驱动程序将引发错误。
Specified as optional指定为可选{ _id?: number };NoIf you do not specify the _id field in an insert operation, the driver adds an _id field value generated by the primary key factory.如果在插入操作中没有指定_id字段,则驱动程序会添加主键工厂生成的_id字段值。

If you must specify the _id field as required in the type you define to represent documents in your collection but you do not want to specify values for the _id field in insert operations, use the OptionalId helper type when you create your collection. 如果必须根据需要在定义的类型中指定_id字段以表示集合中的文档,但不希望在插入操作中为_id字段指定值,请在创建集合时使用OptionalId帮助器类型。The OptionalId type accepts a type parameter as an argument and returns that type with an optional _id field.OptionalId类型接受一个类型参数作为参数,并使用可选的_id字段返回该类型。

The following code snippet defines the IdPet interface, which includes a type for the _id field:以下代码片段定义了IdPet接口,其中包括_id字段的类型:

interface IdPet {
_id: ObjectId;
name: string;
age: number;
}

The following code uses the preceding interface along with the OptionalId type to insert a document without specifying a value for the _id field:以下代码使用前面的接口和OptionalId类型插入文档,而不指定_id字段的值:

const database = client.db("<your database>");
const collection = db.collection<OptionalId<IdPet>>("<your collection>");

myColl.insertOne({
name: "Spot",
age: 2
});

To learn more about the _id field, see The _id Field in the MongoDB manual.要了解有关_id字段的更多信息,请参阅MongoDB手册中的_id字段

To learn more about the types, interfaces, and classes discussed in this section, see the following resources:要了解本节中讨论的类型、接口和类的更多信息,请参阅以下资源:

Find Methods and the _id Field查找方法和_id字段

The find and findOne methods of the Collection class include the _id field in their return type. Collection类的findfindOne方法在其返回类型中包含_id字段。The driver infers the type of the returned _id field based on the type parameter you passed to your Collection instance.驱动程序根据传递给Collection实例的类型参数推断返回的_id字段的类型。

If the type parameter you passed to your Collection instance includes the _id field in its schema, the driver infers that the _id field returned from the method is of the type specified in the schema.如果传递给Collection实例的类型参数在其架构中包含_id字段,则驱动程序推断从方法返回的_id字段属于架构中指定的类型。

However, if the type parameter you passed to your Collection instance does not include the _id field in its schema, the driver infers that the type of the _id field returned from the method is ObjectId.但是,如果传递给Collection实例的类型参数在其架构中不包括_id字段,则驱动程序推断从该方法返回的_id字段的类型为ObjectId

Tip

The type parameter passed to your Collection influences only the type inference of the fields returned from the method. 传递给Collection的类型参数只影响从方法返回的字段的类型推断。The driver does not convert the field to the specified type. 驱动程序未将字段转换为指定的类型。The type of each field in your type parameter's schema should match the type of the corresponding field in the collection.类型参数架构中每个字段的类型都应与集合中相应字段的类型相匹配。

The following code uses the Pet interface to return a document with an _id inferred to be of type ObjectId:以下代码使用Pet接口返回一个_id被推断为ObjectId类型的文档:

const database = client.db("<your database>");
const collection = db.collection<Pet>("<your collection>");

const document = await myColl.findOne({
name: "Spot",
});
const id : ObjectId = document._id;

The following code uses the IdNumberPet interface to return a document with an _id inferred to be of type number:以下代码使用IdNumberPet接口返回一个_id被推断为number类型的文档:

interface IdNumberPet {
_id: number;
name: string;
age: number;
}

const database = client.db("<your database>");
const collection = db.collection<IdNumberPet>("<your collection>");

const document = await myColl.findOne({
name: "Spot",
});
const id : number = document._id;
Important

Projection投影

If you specify a projection in a find method, you should pass a type parameter to your find method that reflects the structure of your projected documents. 如果在查找方法中指定投影,则应向查找方法传递反映投影文档结构的类型参数。Without a type parameter, TypeScript cannot check at compile time that you are using your projected documents safely.如果没有类型参数,TypeScript就无法在编译时检查您是否安全地使用了投影文档。

To show this behavior, the following code snippet passes type checking but raises an error at runtime:为了显示这种行为,以下代码片段通过了类型检查,但在运行时引发了错误:

const doc = await myColl.findOne(
{},
{ projection: { _id: 0, name: 1 } }
);
console.log(doc._id.generationTime);

To catch this error at compile time, pass a type parameter that does not include the _id field to your find method:要在编译时捕获此错误,请将不包括_id字段的类型参数传递给find方法:

interface ProjectedDocument {
name: string
}

const doc = await myColl.findOne<ProjectedDocument>(
{},
{ projection: { _id: 0, name: 1 } }
);
// Compile time error: Property '_id' does not exist on type 'ProjectedDocument'.
console.log(doc._id.generationTime);

To view a runnable TypeScript example that includes a find method applying a projection, see the Find a Document page.要查看包含应用投影的查找方法的可运行TypeScript示例,请参阅查找文档页面。

To learn more about the classes and methods discussed in this section, see the following API documentation:要了解有关本节中讨论的类和方法的更多信息,请参阅以下API文档:

Known Limitations已知限制

Learn about the following TypeScript specific limitations of the Node.js driver:了解Node.js驱动程序的以下TypeScript特定限制:

Recursive Types and Dot Notation递归类型与点表示法

The Node.js driver cannot provide type safety within nested instances of recursive types referenced through dot notation.Node.js驱动程序无法在通过点表示法引用的递归类型的嵌套实例中提供类型安全性。

A recursive type is a type that references itself. 递归类型是一种引用自身的类型。You can update the Pet interface to be recursive by allowing a pet to have its own pet. The following is the recursive Pet interface:您可以通过允许宠物拥有自己的宠物来更新宠物界面,使其递归。以下是递归Pet接口:

interface RecursivePet {
pet?: RecursivePet;
name: string;
age: number;
}
Note

Depth Limit深度限制

The Node.js driver does not traverse nested recursive types when type checking dot notation keys to avoid hitting TypeScript's recursive depth limit.Node.js驱动程序在类型检查点符号键时不遍历嵌套的递归类型,以避免达到TypeScript的递归深度限制。

The following code snippet references a nested instance of the RecursivePet interface with an incorrect type using dot notation, but the TypeScript compiler does not raise a type error:以下代码段使用点表示法引用了具有不正确类型的RecursivePet接口的嵌套实例,但TypeScript编译器不会引发类型错误:

database
.collection<RecursivePet>("<your collection>")
.findOne({ "pet.age": "Spot" });

The following code snippet references a top-level instance of the RecursivePet interface with an incorrect type and raises a type error:以下代码段引用了具有不正确类型的RecursivePet接口的顶级实例,并引发类型错误:

database
.collection<RecursivePet>("<your collection>")
.findOne({ pet: "Spot" });

The error raised by the preceding code snippet is as follows:前面的代码段引发的错误如下:

index.ts(19,59): error TS2769: No overload matches this call.
The last overload gave the following error.
Type 'string' is not assignable to type 'Condition<Pet>'.

If you must have type safety within nested instances of recursive types, you must write your query or update without dot notation.如果必须在递归类型的嵌套实例中具有类型安全性,则必须在不使用句点表示法的情况下编写查询或更新。

To learn more about dot notation, see Dot Notation in the MongoDB manual.要了解更多关于点符号的信息,请参阅MongoDB手册中的点符号

Mutual Recursion相互递归

A mutually recursive type exists when two types contain a property that is of the other's type. 当两个类型包含属于另一个类型的属性时,就存在相互递归的类型。You can update the Pet interface to be mutually recursive by allowing a pet to have a handler, and defining a handler to have a pet. 您可以通过允许宠物拥有一个处理程序,并定义一个处理者来拥有宠物,从而将Pet接口更新为相互递归。The following examples reference the mutually recursive Pet and Handler interfaces:以下示例引用了相互递归的PetHandler接口:

interface Pet {
handler?: Handler;
name: string;
age: number;
}

interface Handler {
pet: Pet;
name: string;
}

The Node.js driver provides type safety for mutually recursive types referenced through dot notation up to a depth of eight. Node.js驱动程序为通过点符号引用的相互递归类型提供类型安全性,深度可达8。The following code snippet assigns a string to a number and raises a type error because the referenced property is at a depth of four:以下代码段将string分配给一个number,并引发类型错误,因为引用的属性深度为4:

database
.collection<Pet>("<your collection>")
.findOne({'handler.pet.handler.pet.age': "four"});

The error raised by the preceding code snippet is as follows:前面的代码段引发的错误如下:

index.ts(19,59): error TS2769: No overload matches this call.
The last overload gave the following error.
Type 'string' is not assignable to type 'Condition<number> | undefined'.

At a depth greater than or equal to eight, TypeScript compiles your code but no longer type checks it. 在大于或等于8的深度处,TypeScript编译代码,但不再对其进行类型检查。The following code assigns a string to a number property but does not cause a compilation error because the referenced property is at a depth of 10:以下代码将string分配给number属性,但不会导致编译错误,因为引用的属性深度为10:

database
.collection<Pet>("<your collection>")
.findOne({'handler.pet.handler.pet.handler.pet.handler.pet.handler.pet.age': "four"});