Docs Home / Node.js Driver

TypeScript Features and LimitationsTypeScript的特性和限制

Overview概述

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

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

All TypeScript features of the driver are optional. All valid JavaScript code written with the driver is also valid TypeScript code.驱动程序的所有TypeScript功能都是可选的。使用驱动程序编写的所有有效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. All classes that accept a type parameter in the driver have the default type Document. The Document interface has the following definition:如果你使用TypeScript,你可以在驱动程序中为某些类指定一个类型。在驱动程序中接受类型参数的所有类都具有默认类型DocumentDocument接口的定义如下:

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. The following code snippet demonstrates this behavior:未在指定类型参数中列出的键将接收any类型。以下代码片段演示了此行为:

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() Example: Full File section of the Find Documents guide.您可以在《查找文档》指南的find()示例:完整文件部分中找到一个代码片段,显示如何为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. 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.从5.0版本开始,默认情况下,Node.js驱动程序不为搜索以点表示的字段的操作提供类型安全。点符号是一种可用于导航嵌套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:以下代码片段定义了ClassificationSet接口,该接口包含一个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 might incorrectly show type errors in valid queries.StrictFilterStrictUpdateFilter类型是实验性的,可能会在有效查询中错误地显示类型错误。

In the following code sample, the filter is assigned a StrictFilter type. 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.在下面的代码示例中,筛选器被分配了StrictFilter类型。给定此筛选器类型,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. The Node.js driver reports a type error because the value of classification.color is a boolean instead of a string.以下示例将StrictUpdateFilter类型分配给更新筛选器。Node.js驱动程序报告类型错误,因为classification.color的值是布尔值而不是字符串。

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

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

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. This mechanism allows your code to compile successfully if the input types are correct.要查询集合或使用包含变量的键执行其他操作,在指定键时必须使用as const断言。如果输入类型正确,此机制允许您的代码成功编译。

The following code snippet defines the ClassificationPet interface and the Mealtime interface. ClassificationPet includes a mealtimes field that contains an array of Mealtime interfaces, each of which includes a time field:以下代码片段定义了ClassificationSet接口和Mealtime接口。ClassificationSet包括一个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. The operation updates the nested time field of the Mealtime instance at index 1. The index position is specified by the variable mealCounter:以下代码段对ClassificationSet文档的集合执行查找和更新操作。该操作更新索引1Mealtime实例的嵌套时间字段。索引位置由变量mealCounter指定:

const mealCounter = 1;

await myColl.findOneAndUpdate(
{ name: "Lassie" },
{ $set: { [`mealtimes.${mealCounter}.time` as const]: '04: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. Omitting the _id field makes the model more generic and reusable and more accurately models the data important to an application. The Node.js driver’s TypeScript integration takes care of adding the _id field to the return types for relevant methods.MongoDB不建议将_id指定为模型的一部分。省略_id字段会使模型更通用、更可重用,并更准确地对应用程序重要的数据进行建模。Node.js驱动程序的TypeScript集成负责将_id字段添加到相关方法的返回类型中。

The following sections provide information about write and read operations that use the _id field.以下部分提供了有关使用_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. The following table describes how different _id field specifications affect insert operations:如何在传递给Collection实例的类型参数中指定_id字段会影响插入操作的行为。下表描述了不同_id字段规范如何影响插入操作:

_id field type字段类型Example 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 and 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. The driver does not convert the field to the specified type. 传递给Collection的类型参数仅影响从该方法返回的字段的类型推断。驱动程序不会将字段转换为指定类型。The type of each field in your type parameter's schema must 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 must 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.如果在find方法中指定投影,则必须向find方法传递一个类型参数,以反映投影文档的结构。如果没有类型参数,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'.编译时错误:类型“ProjectedDocument”上不存在属性“_id”。
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.要查看包含应用投影的find方法的可运行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. 递归类型是一种引用自身的类型。通过允许宠物拥有自己的宠物,您可以将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. The following examples reference the mutually recursive Pet and Handler interfaces:当两个类型包含另一个类型的属性时,就存在相互递归的类型。您可以通过允许宠物有一个处理程序,并定义一个有宠物的处理程序来更新Pet接口,使其相互递归。以下示例引用了相互递归的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. 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:Node.js驱动程序为通过点表示法引用的深度不超过8的相互递归类型提供类型安全。以下代码片段将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. 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:当深度大于或等于8时,TypeScript会编译您的代码,但不再对其进行类型检查。以下代码将string分配给number属性,但不会导致编译错误,因为引用的属性深度为10:

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