TypeScript
項目一覧
Overview
このガイドでは、MongoDB Node.js ドライバーの TypeScript 機能と制限について学習できます。TypeScript は、JavaScript にコンパイルされる、厳密に型指定されたプログラミング言語です。
TypeScript コンパイラーはリアルタイムで型をチェックします。TypeScript をサポートするコード エディターは、オートコンプリートの提案を提供したり、ドキュメントをインラインで表示したり、型関連のエラーを識別したりできます。
ドライバーのすべての TypeScript 機能は任意です。ドライバーを使用して記述されたすべての有効な JavaScript コードは、有効な TypeScript コードでもあります。
詳細については、Typescript のウェブサイトを参照してください。
主な機能
TypeScript を使用する場合は、ドライバー内の一部のクラスの型を指定できます。ドライバー内の型パラメーターを受け入れるすべてのクラスのデフォルトの型は Document
です。Document
インターフェースには、次の定義があります。
interface Document { [key: string]: any; }
すべてのオブジェクト型は Document
インターフェースを拡張します。
オブジェクトタイプの詳細については、Typescript を参照してください。
ドキュメントを拡張する型パラメーター
次のクラスは、Document
インターフェースを拡張するすべての型を受け入れます。
次のように、Document
インターフェースを拡張する型パラメーターを渡すことができます。
1 interface Pet { 2 name: string; 3 age: number; 4 } 5 6 const database = client.db("<your database>"); 7 const collection = database.collection<Pet>("<your collection>");
重要
型パラメーターにないキーは任意の型を受け取ります
指定した型パラメーターにリストされていないキーは、any
型を受け取ります。次のコード スニペットは、この動作を示しています。
1 interface User { 2 email: string; 3 } 4 5 const database = client.db("<your database>"); 6 const myColl = db.collection<User>("<your collection>"); 7 myColl.find({ age: "Accepts any type!" });
任意の型パラメーター
次のクラスは、すべての型パラメーターを受け入れます。
FindCursor
クラスの型を指定する方法を示すコード スニペットは、 複数のドキュメントの検索の使用例に記載されています。
型の安全性とドット表記
バージョン 5.0 以降、Node.js ドライバーは、デフォルトで、ドット表記で表現されたフィールドを検索する操作に対して型の安全性を提供しません。ドット表記は、ネストされた JSON オブジェクトをナビゲートするために使用できる構文です。クエリに渡すフィルターを作成する場合、ドット表記で表現されたフィールドに誤った型の値を指定しても、ドライバーは型エラーを生成しません。
次のコード スニペットは、犬と猫の属と色を指定できる classification
フィールドを含む ClassificationPet
インターフェースを定義します。
interface ClassificationPet { name: string; age: number; classification: { genus: "Canis" | "Felis"; color: string }; }
次のコード サンプルでは、classification.color
の値が文字列ではなくブール値であるにもかかわらず、ドライバーは型エラーを生成しません。
await myColl.findOneAndDelete({ "classification.color": false });
フィルターを StrictFilter
または StrictUpdateFilter
型として構築することで、型チェックを有効にすることができます。
警告
StrictFilter
とStrictUpdateFilter
型は実験的なものであり、有効なクエリでは型エラーが発生しないはずです。
次のコード サンプルでは、フィルターに StrictFilter
型が割り当てられています。このフィルター型の場合、classification.color
の値が文字列 ではなくブール値であるため、Node.js ドライバーは型エラーを報告します。
const filterPredicate: StrictFilter<ClassificationPet> = { "classification.color": false }; await myColl.findOneAndDelete(filterPredicate);
次の例では、アップデート フィルターに StrictUpdateFilter
型を割り当てます。Node.js ドライバーは、 classification.color
の値が文字列ではなくブール値であるため、型エラーを報告します。
const updateFilter: StrictUpdateFilter<ClassificationPet> = { $set: { "classification.color": false } } await pets.updateOne({}, updateFilter);
変数を組み込んだキーの参照
コレクションをクエリしたり、変数を組み込んだキーを使用して別の操作を実行したりするには、キーを指定するときに as const
アサーションを使用する必要があります。このメカニズムにより、入力型が正しい場合にコードを正常にコンパイルできます。
次のコード スニペットは、ClassificationPet
インターフェースと Mealtime
インターフェースを定義します。ClassificationPet
には、Mealtime
インターフェースの配列を含む mealtimes
フィールドが含まれており、各インターフェースには time
フィールドが含まれています。
interface ClassificationPet { name: string; mealtimes: Mealtime[]; } interface Mealtime{ time: string; amount: number; }
次のコード スニペットは、ClassificationPet
ドキュメントのコレクションに対して検索とアップデートの操作を実行します。この操作は、インデックス 1
にある Mealtime
インスタンスのネストされた time
フィールドをアップデートします。インデックス位置は変数mealCounter
によって指定されます。
const mealCounter = 1; await myColl.findOneAndUpdate( { name: "Lassie" }, { $set: { [`mealtimes.${mealCounter}.time` as const]: '4:00 PM' } }, );
ドット表記の詳細については、MongoDB マニュアルの「ドット表記 」を参照してください。
Node.js ドライバーのドット表記の制限の詳細については、「再帰型とドット表記 」セクションを参照してください。
_id フィールドとの連携
MongoDB では、モデルの一部として _id
を指定することは推奨されません。_id
フィールドを省略すると、モデルはより汎用的かつ再利用可能になり、アプリケーションにとって重要なデータをより正確にモデル化します。Node ドライバーの TypeScript 統合により、関連するメソッドの戻り値の型に _id
フィールドが追加されます。
次のセクションでは、_id
フィールドを使用する書込み操作と読み取り操作について説明します。
挿入操作と _id フィールド
Collection
インスタンスに渡される型パラメーターで _id
フィールドをどのように指定するかは、挿入操作の動作に影響します。次の表は、さまざまな _id
フィールドの仕様が挿入操作にどのように影響するかを示しています。
_id フィールド型 | 例型 | 挿入時に必要 | 挿入時の動作 |
---|---|---|---|
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. |
コレクション内のドキュメントを表すために定義する型で必須として _id
フィールドを指定する必要があり、挿入操作で _id
フィールドの値を指定したくない場合は、コレクションを作成するときに OptionalId
ヘルパー型を使用します。OptionalId
型は、型パラメータを引数として受け入れ、任意の _id
フィールドとともにその型を返します。
次のコード スニペットは、_id
フィールドの型を含む IdPet
インターフェースを定義します。
interface IdPet { _id: ObjectId; name: string; age: number; }
次のコードでは、前述のインターフェースとOptionalId
型を使用して、 _id
フィールドに値を指定せずにドキュメントを挿入します。
const database = client.db("<your database>"); const collection = db.collection<OptionalId<IdPet>>("<your collection>"); myColl.insertOne({ name: "Spot", age: 2 });
_id
フィールドの詳細については、MongoDB マニュアルの「 _id フィールド」を参照してください。
このセクションで説明した型、インターフェース、クラスの詳細については、次のリソースを参照してください。
OptionalId API documentation
PkFactory API ドキュメント
ObjectId ソースコード
メソッドと _id フィールドの検索
Collection
クラスの find
メソッドと findOne
メソッドには、戻り値の型に _id
フィールドが含まれます。ドライバーは、Collection
インスタンスに渡した型パラメーターに基づいて、返される _id
フィールドの型を推測します。
Collection
インスタンスに渡した型パラメーターのスキーマに _id
フィールドが含まれている場合、ドライバーはメソッドから返された _id
フィールドがスキーマで指定された型であると推測します。
ただし、Collection
インスタンスに渡した型パラメーターのスキーマに _id
フィールドが含まれていない場合、ドライバーはメソッドから返される _id
フィールドの型が ObjectId
であると推測します。
Tip
Collection
に渡される型パラメータは、メソッドから返されるフィールドの型推論にのみ影響します。 ドライバーは、指定された型にフィールドを変換しません。 型パラメータのスキーマ内の各フィールドの型は、コレクション内の対応するフィールドの型と一致する必要があります。
次のコードは、 Pentインターフェースを使用して、 _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;
次のコードは、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;
重要
プロジェクション
find メソッドでプロジェクションを指定する場合は、プロジェクションされるドキュメントの構造を反映する型パラメーターを find メソッドに渡す必要があります。 型パラメータがないと、 Typescriptはコンパイル時にプロジェクションされたドキュメントが安全に使用されているかどうかを確認できません。
この動作を示すために、次のコード スニペットは型のチェックに合格しますが、実行時にエラーが発生します。
const doc = await myColl.findOne( {}, { projection: { _id: 0, name: 1 } } ); console.log(doc._id.generationTime);
コンパイル時にこのエラーをキャッチするには、_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);
プロジェクションを適用する find メソッドを含む実行可能な TypeScript の例を表示するには、「ドキュメントの検索」ページを参照してください。
このセクションで説明するクラスとメソッドについて詳しくは、次の API ドキュメントを参照してください。
既知の制限
Node.js ドライバーの次の TypeScript 固有の制限について説明します。
再帰型とドット表記
Node.js ドライバーは、ドット表記で参照される再帰型のネストされたインスタンス内で型の安全性を確保できません。
再帰型とは、自分自身を参照する型です。 ポッドが独自のプライベートを持つことを許可することで、 Petインターフェースを再帰的に更新できます。 以下は、再帰的なPet
インターフェースです。
interface RecursivePet { pet?: RecursivePet; name: string; age: number; }
注意
深度制限
Node.js ドライバーは、TypeScript の再帰深度制限に達するのを避けるために、ドット表記キーの型チェック時にネストされた再帰型を走査しません。
次のコード スニペットは、ドット表記を使用して間違った型を持つRecursivePatインターフェースのネストされたインスタンスを参照しますが、 Typescriptコンパイラーは型エラーを生成しません。
database .collection<RecursivePet>("<your collection>") .findOne({ "pet.age": "Spot" });
次のコード スニペットは、間違った型を持つ RecursivePet
インターフェースの最上位インスタンスを参照し、型エラーを発生させます。
database .collection<RecursivePet>("<your collection>") .findOne({ pet: "Spot" });
上記のコード スニペットによって発生するエラーは次のとおりです。
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>'.
再帰型のネストされたインスタンス内で型の安全性を確保する必要がある場合は、ドット表記を使用せずにクエリまたはアップデートを記述する必要があります。
ドット表記の詳細については、MongoDB マニュアルの「ドット表記 」を参照してください。
相互再帰
相互再帰型は、2 つの型にもう 1 つの型であるプロパティが含まれている場合に存在します。 Perlインターフェースを相互再帰的に更新するには、Perl がハンドラーを持つことを許可し、ペインを含むハンドラーを定義します。 次の例えでは、相互再帰的なPet
インターフェースとHandler
インターフェースを参照します。
interface Pet { handler?: Handler; name: string; age: number; } interface Handler { pet: Pet; name: string; }
Node.js ドライバーは、ドット表記法で参照される相互再帰型に対して、最大「8」の深度までの型の安全性を提供します。次のコード スニペットは、string
を number
に割り当て、参照されるプロパティの深度が「4」であるため、型エラーを発生させます。
database .collection<Pet>("<your collection>") .findOne({'handler.pet.handler.pet.age': "four"});
上記のコード スニペットによって発生するエラーは次のとおりです。
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'.
深度が「8」以上の場合、TypeScript はコードをコンパイルしますが、型チェックは行いません。次のコードは、string
を number
プロパティに割り当てますが、参照されるプロパティの深度が「10」であるため、コンパイル エラーは発生しません。
database .collection<Pet>("<your collection>") .findOne({'handler.pet.handler.pet.handler.pet.handler.pet.handler.pet.age': "four"});