Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(DOCSP-20071) Update TS Limitations #275

Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
70649c4
remove limitation and add admonition
biniona-mongodb Jan 11, 2022
fd76f80
wip
biniona-mongodb Jan 11, 2022
438156c
wip
biniona-mongodb Jan 11, 2022
42cae8c
wip
biniona-mongodb Jan 11, 2022
fc3537b
wip
biniona-mongodb Jan 11, 2022
1853bf5
grammar check, move to own section
biniona-mongodb Jan 11, 2022
ea95abc
proofread
biniona-mongodb Jan 11, 2022
b35c0d9
CC - edits part 1
biniona-mongodb Jan 12, 2022
a758cdd
cc - break recursive example intro into sentence
biniona-mongodb Jan 12, 2022
4ba4c20
typo
biniona-mongodb Jan 12, 2022
47ec306
consistency
biniona-mongodb Jan 12, 2022
079cd5e
cc - edits
biniona-mongodb Jan 12, 2022
1be07ca
update subheadings
biniona-mongodb Jan 12, 2022
f61c9f1
test
biniona-mongodb Jan 12, 2022
7e36683
Revert "test"
biniona-mongodb Jan 12, 2022
f2ec69e
any -> all
biniona-mongodb Jan 12, 2022
eb77c53
cc - discussion
biniona-mongodb Jan 12, 2022
2d3cc37
edits
biniona-mongodb Jan 12, 2022
b48748e
warning
biniona-mongodb Jan 12, 2022
e1648d0
cc - edits
biniona-mongodb Jan 13, 2022
ad6c58d
Merge branch 'master' into DOCSP-20071-Support-Dot-Notation-TS
biniona-mongodb Jan 13, 2022
f45b0a8
update limitations for Node PR #3102
biniona-mongodb Jan 18, 2022
fe64c9f
typo
biniona-mongodb Jan 18, 2022
353416a
proofread
biniona-mongodb Jan 18, 2022
4bfa35e
wip
biniona-mongodb Jan 18, 2022
f7967df
grammar-check
biniona-mongodb Jan 18, 2022
e3f65ec
updates from slack thread
biniona-mongodb Jan 19, 2022
8bd69e4
proofread
biniona-mongodb Jan 19, 2022
06de329
proofread
biniona-mongodb Jan 19, 2022
8fb218b
cc - edits
biniona-mongodb Jan 20, 2022
6276c5d
proofread, spell check, grammar check
biniona-mongodb Jan 20, 2022
36730a5
cc - edits
biniona-mongodb Jan 24, 2022
67dc810
move header out of include to avoid h3
biniona-mongodb Jan 24, 2022
cc4fdb1
tweak
biniona-mongodb Jan 24, 2022
ad3b47e
dp - edits
biniona-mongodb Jan 31, 2022
59ed5e0
tweaks
biniona-mongodb Jan 31, 2022
7a1748f
proofread
biniona-mongodb Jan 31, 2022
8c97f31
tweak
biniona-mongodb Jan 31, 2022
11ba220
tweak example as genus and family are not independent
biniona-mongodb Jan 31, 2022
5a41582
dp - edit
biniona-mongodb Jan 31, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions source/code-snippets/typescript/dot-notation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ const collection = database.collection<TestType>("<your collection>");
await collection.updateOne({}, { $set: { field: { nested: "A string" } } });
// end-error
// start-no-key
interface TestNumber {
myNumber: number;
interface User {
email: string;
}

const database = client.db("<your db>");
const collection = db.collection<TestNumber>("...");
collection.find({ someRandomKey: "Accepts any type!" });
const database = client.db("<your database>");
biniona-mongodb marked this conversation as resolved.
Show resolved Hide resolved
const collection = db.collection<User>("<your collection>");
collection.find({ age: "Accepts any type!" });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a note that this will probably need to change soon to something like { $unknownOperator: "Accepts any type!" } because we actually have a user submitted fix to make sure that we validate unknown keys that aren't $-prefixed but allow all $-prefixed keys for forward compatibility with new server operators. Right now the corresponding note is correct, but once we release a fix, it will need to be updated.

(see mongodb/node-mongodb-native#3115)

Copy link
Contributor Author

@biniona-mongodb biniona-mongodb Jan 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Daria! There is a ticket to add the "query nested fields without dot notation" example back to a different section of the documentation (DevED-DBX agreed that TS page seemed only tangentially related to dot notation and was not the correct place for this content).

The page that should explain to readers how to use Dot Notation is the Update Arrays in a Document Page (linking to Java), however it seems like the corresponding Node page does not explicitly discuss dot notation. I've created a ticket to add this content .

As this PR has already been through a few internal reviews and has grown to be fairly large, I think it is best to close out this pull request and handle the upcoming changes as part of a new task (any substantial additions will require an additional copy review which will take a decent amount of time as the diff for this PR has become pretty big).

Sorry for the long response! Let me know if I have failed to address any of your concerns.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with doing the $-prefix updates later, but I really feel like the current page could benefit from a working example of dot notation type hinting use (i.e., show how having the wrong type in a non-recursive collection definition raises a typescript error)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I agree an example of working dot notation type checking would benefit readers. I've added a "dot notation" subsection to the Features section Let me know if this addresses your concerns!

// end-no-key
1 change: 0 additions & 1 deletion source/code-snippets/typescript/extend-document.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
interface Pet {
name: string;
age: number;
cute: true;
}

const database = client.db("<your database>");
Expand Down
18 changes: 0 additions & 18 deletions source/code-snippets/typescript/note-on-dot-notation.ts

This file was deleted.

108 changes: 25 additions & 83 deletions source/fundamentals/typescript.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,26 @@ All classes that accept a type parameter in the driver have the default type
[key: string]: any;
}

Any object type can extend the ``Document`` interface.
All object types extend the ``Document`` interface.

For more information on object types, see the
`TypeScript handbook <https://www.typescriptlang.org/docs/handbook/2/objects.html>`__.

Extend Document
~~~~~~~~~~~~~~~
Type Parameters that Extend Document
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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

.. _node-mongodb-type-paramaters-extend-document:

- `Collection <{+api+}/classes/Collection.html>`__
- `ChangeStream <{+api+}/classes/ChangeStream.html>`__

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

.. _mongodb-node-typescript-pet-interface:

.. literalinclude:: /code-snippets/typescript/extend-document.ts
:language: typescript
:linenos:
Expand All @@ -67,10 +71,16 @@ You can pass a type parameter that extends the ``Document`` interface like this:
:start-after: start-no-key
:end-before: end-no-key

Any Type
~~~~~~~~
To view an example of a mutually recursive type, which is not supported by the
:ref:`preceding classes <node-mongodb-type-paramaters-extend-document>`,
see the :ref:`<node-driver-limitations-mutual-recursion>` section.

Type Parameters of Any Type
~~~~~~~~~~~~~~~~~~~~~~~~~~~

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

The following classes accept any type parameter:
.. _node-mongodb-type-paramaters-any-type:

- `FindCursor <{+api+}/classes/FindCursor.html>`__
- `AggregationCursor <{+api+}/classes/AggregationCursor.html>`__
Expand All @@ -79,81 +89,13 @@ You can find a code snippet that shows how to specify a type for the ``FindCurso
class in the
:ref:`Find Multiple Documents Usage Example <node-driver-find-usage-example-code-snippet>`.

Limitations
-----------

.. _node-driver-typescript-limitations-dot-notation:

The driver cannot infer the type of values with keys containing **dot
notation**. Dot notation is a property access syntax for navigating BSON objects.
Click on the tabs to see code snippets that highlight this behavior:

.. tabs::

.. tab:: Dot Notation
:tabid: dot-notation

The following code snippet does not raise a type error:

.. literalinclude:: /code-snippets/typescript/dot-notation.ts
:language: typescript
:linenos:
:start-after: start-no-error
:end-before: end-no-error

.. tab:: Nested Objects
:tabid: nested-objects

The following code snippet raises a type error:

.. literalinclude:: /code-snippets/typescript/dot-notation.ts
:language: typescript
:linenos:
:start-after: start-error
:end-before: end-error

This is the error:

.. code-block:: text
To view an example of a mutually recursive type, which is not supported by the
:ref:`preceding classes <node-mongodb-type-paramaters-any-type>`,
see the :ref:`<node-driver-limitations-mutual-recursion>` section.

Type 'string' is not assignable to type 'number'.

Despite the lack of type safety, we still recommend that you use dot notation to
access nested fields in query and update documents when you use TypeScript. You
must manually check that your nested field values have your intended type.

.. note:: Reason To Use Dot Notation

In the MongoDB Query Language, you must match a subdocument exactly
when specifying subdocuments in a query. Dot notation allows you to query
nested fields without matching subdocuments exactly.

To show this behavior, lets say you have a collection containing
only the following document:

.. code-block:: json

{ field: { s1: "hi", s2: "bye" } }

The following query returns no results from this collection, as the value of
``field`` does not exactly match ``{ s1: "hi" }``:

.. literalinclude:: /code-snippets/typescript/note-on-dot-notation.ts
:language: typescript
:linenos:
:start-after: start-no-doc
:end-before: end-no-doc

The following queries both return your document:

.. literalinclude:: /code-snippets/typescript/note-on-dot-notation.ts
:language: typescript
:linenos:
:start-after: start-doc
:end-before: end-doc
.. _node-driver-limitations:

The syntax of the query that does not use dot notation is cumbersome and hard
to understand, and may not be worth the type safety obtained from
avoiding dot notation.
Limitations For Driver Version {+version+}
ccho-mongodb marked this conversation as resolved.
Show resolved Hide resolved
biniona-mongodb marked this conversation as resolved.
Show resolved Hide resolved
----------------------------------

For more information on dot notation, see :manual:`the MongoDB Manual </core/document/#dot-notation>`.
.. include:: includes/limitations/{+version+}.rst
biniona-mongodb marked this conversation as resolved.
Show resolved Hide resolved
113 changes: 113 additions & 0 deletions source/includes/limitations/4.3.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
Learn about the following TypeScript specific limitations of
version {+version+} of the {+driver-short+}:

- :ref:`The {+driver-short+} is unable to provide type safety for references to nested instances of recursive types specified through dot notation. <node-driver-recursive-types-dot-notation>`
- :ref:`The {+driver-short+} does not support mutual recursion. <node-driver-limitations-mutual-recursion>`
biniona-mongodb marked this conversation as resolved.
Show resolved Hide resolved

The TypeScript specific limitations of the {+driver-short+} relate to **recursive types**.
A recursive type is a type that references itself. You can update
the :ref:`Pet <mongodb-node-typescript-pet-interface>` interface
to be recursive by allowing a pet to have its own pet. The following is the
recursive ``Pet`` interface:

.. _node-driver-limitations-recursive-pet:

.. code-block:: typescript
:emphasize-lines: 2

interface RecursivePet {
pet?: RecursivePet;
name: string;
age: number;
}
biniona-mongodb marked this conversation as resolved.
Show resolved Hide resolved

.. _node-driver-recursive-types-dot-notation:

Recursive Types and Dot Notation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The {+driver-short+} cannot provide type safety within nested instances of
recursive types referenced through **dot notation**. Dot notation is a
syntax you can use to navigate nested JSON objects.

.. note:: Depth Limit

The {+driver-short+} 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
:ref:`RecursivePet <node-driver-limitations-recursive-pet>` interface
with an incorrect type using dot notation, but the TypeScript compiler
does not raise an error:

.. code-block:: typescript
:emphasize-lines: 3

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:
biniona-mongodb marked this conversation as resolved.
Show resolved Hide resolved

.. code-block:: typescript
:emphasize-lines: 3

database
.collection<RecursivePet>("your-collection")
biniona-mongodb marked this conversation as resolved.
Show resolved Hide resolved
.findOne({ pet: "Spot" });

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

.. code-block:: text
biniona-mongodb marked this conversation as resolved.
Show resolved Hide resolved

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
:manual:`Dot Notation </core/document/#dot-notation>`
in the MongoDB manual.

.. _node-driver-limitations-mutual-recursion:

Mutual Recursion
~~~~~~~~~~~~~~~~

You cannot specify a mutually recursive type as a type parameter in version
{+version+} of the driver.
biniona-mongodb marked this conversation as resolved.
Show resolved Hide resolved

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

.. code-block:: text

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

A mutually recursive type exists when two types contain a property that is of
the other's type. You can update the
:ref:`Pet <mongodb-node-typescript-pet-interface>` interface
to be mutually recursive by allowing a pet to have a handler, and defining a
handler to have a pet. The following is the mutually
recursive ``Pet`` interface:
biniona-mongodb marked this conversation as resolved.
Show resolved Hide resolved

.. code-block:: typescript
:emphasize-lines: 2, 8

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

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

If you must apply a mutually recursive type to your classes, use version 4.2 of
the {+driver-short+}.
6 changes: 0 additions & 6 deletions source/usage-examples/bulkWrite.txt
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,6 @@ to ``bulkWrite()`` includes examples of ``insertOne``, ``updateMany``, and
:language: typescript
:linenos:

.. important:: Dot Notation Loses Type Safety

You lose type-safety for values when you use dot notation in keys. For
more information, see our guide on
:ref:`TypeScript in the driver <node-driver-typescript-limitations-dot-notation>`.

When you run the preceding example, you should see the following output:

.. code-block:: javascript
Expand Down