Docs Menu

TypeScript

On this page

  • Overview
  • Features
  • Type Parameters that Extend Document
  • Type Parameters of Any Type
  • Type Safety and Dot Notation
  • Working with the _id Field
  • Insert Operations and the _id Field
  • Find Methods and the _id Field
  • Known Limitations
  • Recursive Types and Dot Notation
  • Mutual Recursion

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.

All TypeScript features of the driver are optional. All valid JavaScript code written with the driver is also valid TypeScript code.

For more information, see the TypeScript website.

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:

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

All object types extend the Document interface.

For more information on object types, see the TypeScript handbook.

The following classes accept all types that both extend the Document interface and are not mutually recursive:

You can pass a type parameter that extends the Document interface like this:

1interface Pet {
2 name: string;
3 age: number;
4}
5
6const database = client.db("<your database>");
7const 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:

1interface User {
2 email: string;
3}
4
5const database = client.db("<your database>");
6const collection = db.collection<User>("<your collection>");
7collection.find({ age: "Accepts any type!" });

To view an example of a mutually recursive type, which is not supported by the preceding classes, see the Mutual Recursion section.

The following classes accept all type parameters that are not mutually recursive:

You can find a code snippet that shows how to specify a type for the FindCursor class in the Find Multiple Documents Usage Example.

To view an example of a mutually recursive type, which is not supported by the preceding classes, see the Mutual Recursion section.

If you specify a query or update with dot notation, the Node.js driver provides type safety if your query or update does not reference a nested instance of a recursive type. Dot notation is a syntax you can use to navigate nested JSON objects.

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:

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

The following code snippet correctly raises a type error when specifying the genus of an unsupported animal in a query:

database
.collection<ClassificationPet>("<your collection>")
.find({ "classification.genus": "Sylvilagus" });

The type error raised by the preceding code snippet is as follows:

No overload matches this call.
...
Type '"Sylvilagus"' is not assignable to type 'Condition<"Canis" | "Felis">'.

To learn more about dot notation, see Dot Notation in the MongoDB manual.

To learn more about the limitations of dot notation in the Node.js driver, see the Recursive Types and Dot Notation section.

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 driver’s TypeScript integration takes care of adding the _id field to the return types for relevant methods.

If you need to work with the _id field in your models, see the below sections for information on write and read operations.

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:

_id field type
Example Type
Required on insert
Behavior on insert
Unspecified
Not applicable
No
The driver creates an ObjectId value for each inserted document.
Specified
{ _id: number };
Yes
If you do not specify a value for the _id field in an insert operation, the driver raises an error.
Specified as optional
{ _id?: number };
No
If you do not specify the _id field in an insert operation, the driver adds an _id field value generated by the primary key factory.

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. The OptionalId type accepts a type parameter as an argument and returns that type with an optional _id field.

The following code snippet defines the IdPet interface, which includes a type for the _id field:

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:

const database = client.db("<your database>");
const collection = db.collection<OptionalId<IdPet>>("<your collection>");
collection.insertOne({
name: "Spot",
age: 2
});

To learn more about the _id field, see The _id Field in the MongoDB manual.

To learn more about the types, interfaces, and classes discussed in this section, see the following resources:

The find and findOne methods of the Collection class include the _id field in their return type.

If the type parameter you passed to your Collection instance includes the _id field, the type of the _id field in the values returned from the find methods is the same as the type of the _id field in your type parameter.

If the type parameter you passed to your Collection instance does not include the _id field, the driver gives the _id field in the values returned from the find methods the type ObjectId.

The following code uses the Pet interface to return a document with an _id of type ObjectId:

const database = client.db("<your database>");
const collection = db.collection<Pet>("<your collection>");
const document = await collection.findOne({
name: "Spot",
});
const id : ObjectId = document._id;

The following code uses the IdNumberPet interface to return a document with an _id field of type 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 collection.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.

To show this behavior, the following code snippet passes type checking but raises an error at runtime:

const doc = await collection.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:

interface ProjectedDocument {
name: string
}
const doc = await collection.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.

To learn more about the classes and methods discussed in this section, see the following API documentation:

Learn about the following TypeScript specific limitations of the Node.js driver:

Important
Impacted Versions
  • 4.3
  • 4.4

The Node.js driver cannot provide type safety within nested instances of recursive types referenced through dot notation.

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:

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.

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:

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:

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.

Important
Impacted Versions
  • 4.3
  • 4.4

You cannot specify a mutually recursive type as a type parameter.

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 are the mutually recursive Pet and Handler interfaces:

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

If you specify a mutually recursive type, the TypeScript compiler raises the following error:

error TS2615: Type of property 'r' circularly references itself in mapped type '{ [Key in keyof MutuallyRecursive]...

If you must apply a mutually recursive type to your classes, use version 4.2 of the Node.js driver.

←  Time SeriesUTF-8 Validation →
Give Feedback
© 2022 MongoDB, Inc.

About

  • Careers
  • Investor Relations
  • Legal Notices
  • Privacy Notices
  • Security Information
  • Trust Center
© 2022 MongoDB, Inc.