TypeScript
Nesta página
Visão geral
Neste guia, você pode aprender sobre os recursos e limitações do TypeScript do driver MongoDB Node.js. TypeScript é uma linguagem de programação fortemente digitada que compila ao JavaScript.
O compilador TypeScript oferece verificação de tipo em tempo real. Editores de código que suporte TypeScript pode fornecer sugestões de preenchimento automático, exibir documentação embutida e identificar erros relacionados ao tipo.
Todas as funcionalidades do TypeScript do condutor são opcionais. Todo código JavaScript válido escrito com o driver também é um código TypeScript válido.
Para obter mais informações, consulte o site do TypeScript.
Características
Se você usar o TypeScript, poderá especificar um tipo para algumas classes no driver. Todas as classes que aceitam um parâmetro de tipo no driver têm o tipo padrão Document
. A interface Document
tem a seguinte definição:
interface Document { [key: string]: any; }
Todos os tipos de objetos estendem a interface Document
.
Para obter mais informações sobre tipos de objetos, consulte o manual do TypeScript.
Parâmetros de tipo que estendem o documento
As seguintes classes aceitam todos os tipos que estendem a interface Document
:
Você pode passar um parâmetro de tipo que estenda a interface Document
como esta:
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>");
Importante
Chaves que não estão no parâmetro Tipo recebem qualquer tipo
As chaves não listadas no parâmetro de tipo especificado recebem o tipo any
. O seguinte trecho de código demonstra este comportamento:
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!" });
Digite parâmetros de qualquer tipo
As seguintes classes aceitam todos os parâmetros do tipo:
Você pode encontrar um trecho de código que mostra como especificar um tipo para a classe FindCursor
no Exemplo de uso do Find Multiple Documents.
Digite Segurança e Notação de Ponto
A partir da versão 5.0, por padrão, o driver Node.js não oferece segurança de tipo para operações que procuram em campos expressos em notação de ponto. A anotação de ponto é uma sintaxe que você pode utilizar para navegar por objetos JSON aninhados. Quando você constrói um filtro para passar para uma query, o driver não emitirá um erro de tipo, mesmo que você especifique um valor digitado incorretamente para um campo expresso em notação de ponto.
O seguinte trecho de código define a interface ClassificationPet
, que inclui um campo classification
que permite especificar o gênero e a cor dos cães e gatos:
interface ClassificationPet { name: string; age: number; classification: { genus: "Canis" | "Felis"; color: string }; }
O driver não gera um erro de tipo para o seguinte exemplo de código, mesmo que o valor de classification.color
seja um booleano em vez de uma string:
await myColl.findOneAndDelete({ "classification.color": false });
Você pode habilitar a verificação de tipo construindo filtros como tipos StrictFilter
ou StrictUpdateFilter
.
Aviso
Os tipos StrictFilter
e StrictUpdateFilter
são experimentais e podem mostrar erros de tipo em queries válidas onde não deve haver nenhum.
No exemplo de código a seguir, o filtro é atribuído a um tipo StrictFilter
. Dado esse tipo de filtro, o driver do Node.js informa um erro de tipo porque o valor de classification.color
é um booleano em vez de uma string.
const filterPredicate: StrictFilter<ClassificationPet> = { "classification.color": false }; await myColl.findOneAndDelete(filterPredicate);
O exemplo a seguir atribui um tipo StrictUpdateFilter
a um filtro de atualização. O driver Node.js relata um erro de tipo porque o valor de classification.color
é booleano em vez de uma string.
const updateFilter: StrictUpdateFilter<ClassificationPet> = { $set: { "classification.color": false } } await pets.updateOne({}, updateFilter);
Chaves de referência que incorporam variáveis
Para fazer query em uma coleção ou executar outra operação com uma chave que incorpore variáveis, você deve utilizar uma afirmação do as const
ao especificar a chave. Esse mecanismo permite que seu código seja compilado com sucesso se os tipos de entrada estiverem corretos.
O seguinte trecho de código define a interface ClassificationPet
e a interface Mealtime
. ClassificationPet
inclui um campo mealtimes
que contém uma array de Mealtime
interfaces, cada uma delas inclui um campo time
:
interface ClassificationPet { name: string; mealtimes: Mealtime[]; } interface Mealtime{ time: string; amount: number; }
O seguinte trecho de código executa uma operação de multa e atualização em uma coleção de documentos ClassificationPet
. A operação atualiza o campo time
aninhado da instância Mealtime
no índice 1
. A posição do índice é especificada pela variável mealCounter
:
const mealCounter = 1; await myColl.findOneAndUpdate( { name: "Lassie" }, { $set: { [`mealtimes.${mealCounter}.time` as const]: '4:00 PM' } }, );
Para saber mais sobre notação de pontos, consulte Notação de pontos no manual do MongoDB.
Para saber mais sobre as limitações da notação de ponto no driver Node.js, consulte a seção Tipos Recursivos e Notação de Ponto .
Trabalhando com o campo _id
O MongoDB não recomenda especificar o _id
como parte do seu modelo. A omissão do campo _id
torna o modelo mais genérico, reutilizável e com mais precisão modela os dados importantes para um aplicativo. Integração TypeScript driver Node trata de adicionar o campo _id
aos tipos de retorno para métodos relevantes.
As seções a seguir fornecem informações sobre operações de escrita e leitura que utilizam o campo _id
.
Inserir Operações e o Campo _id
Como você especifica o campo _id
nos parâmetros de tipo passados para a instância Collection
afeta o comportamento das operações de inserção. A tabela a seguir descreve como especificações diferentes do campo _id
afetam as operações de inserção:
_id tipo de campo | Tipo de exemplo | Necessário na inserção | Comportamento ao inserir |
---|---|---|---|
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. |
Se você precisar especificar o campo _id
como obrigatório no tipo definido para representar documentos na coleção, mas não quiser especificar valores para o campo _id
nas operações de inserção, use o tipo auxiliar OptionalId
ao criar a coleção. O tipo OptionalId
aceita um parâmetro de tipo como um argumento e retorna este tipo com um campo opcional _id
.
O seguinte trecho de código define a interface IdPet
, que inclui um tipo para o campo _id
:
interface IdPet { _id: ObjectId; name: string; age: number; }
O código a seguir usa a interface anterior junto com o tipo OptionalId
para inserir um documento sem especificar um valor para o campo _id
:
const database = client.db("<your database>"); const collection = db.collection<OptionalId<IdPet>>("<your collection>"); myColl.insertOne({ name: "Spot", age: 2 });
Para saber mais sobre o campo _id
, consulte O campo _id no manual do MongoDB.
Para saber mais sobre os tipos, interfaces e classes discutidos nesta seção, consulte os seguintes recursos:
Documentação da API do OptionalId
Documentação da API do PkFactory
código-fonte ObjectId
Encontrar métodos e o campo _id
Os métodos find
e findOne
da classe Collection
incluem o campo _id
em seu tipo de retorno. O driver infere o tipo do campo _id
retornado com base no parâmetro type que você passou para sua instância Collection
.
Se o parâmetro de tipo que você passou para sua instância do Collection
incluir o campo _id
em seu esquema, o driver infere que o campo _id
retornou do método é do tipo especificado no esquema.
No entanto, se o parâmetro de tipo que você passou para sua instância Collection
não incluir o campo _id
em seu esquema, o driver infere que o tipo do campo _id
retornado do método é ObjectId
.
Dica
O parâmetro de tipo passado para seu Collection
influencia somente o tipo inferência dos campos retornados pelo método. O driver não converte o campo para o tipo especificado. O tipo de cada campo no seu tipo
O esquema do parâmetro deve corresponder ao tipo do campo correspondente na
coleção.
O código a seguir usa a interface Pet para retornar um documento com um _id
inferido como sendo do tipo 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;
O código a seguir usa a interface IdNumberPet
para retornar um documento com um _id
inferido como sendo do tipo 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;
Importante
Projeção
Se você especificar uma projeção em um método find, deverá passar um parâmetro de tipo para o método find que reflita a estrutura dos documentos projetados. Sem um parâmetro de tipo, o TypeScript não pode verificar no momento da compilação se você está usando seus documentos projetados com segurança.
Para mostrar esse comportamento, o seguinte trecho de código passa por uma verificação de tipo, mas gera um erro no tempo de execução:
const doc = await myColl.findOne( {}, { projection: { _id: 0, name: 1 } } ); console.log(doc._id.generationTime);
Para detectar esse erro no momento da compilação, passe um parâmetro de tipo que não inclua o campo _id
para seu método de pesquisa:
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);
Para visualizar um exemplo executável do TypeScript que inclui um método find que aplica uma projeção, consulte a página Localizar um Documento.
Para saber mais sobre as classes e os métodos discutidos nesta seção, consulte a seguinte documentação da API:
Limitações conhecidas
Saiba mais sobre as seguintes limitações específicas do TypeScript do driver Node.js:
Tipos recursivos e notação de ponto
O driver Node.js não pode fornecer segurança de tipo em instâncias aninhadas de tipos recursivos referenciados por meio de notação de ponto.
Um tipo recursivo é um tipo que referencia a si mesmo. É possível atualizar a interface Pet para ser recursiva, permitindo que um Pet tenha seu próprio Pet. A seguir está a interface Pet
recursiva:
interface RecursivePet { pet?: RecursivePet; name: string; age: number; }
Observação
Limite de profundidade
O driver do Node.js não atravessa tipos recursivos aninhados ao verificar chaves de notação de ponto para evitar atingir o limite de profundidade recursiva do TypeScript.
O seguinte trecho de código faz referência a uma instância aninhada da interface RecursivePet com um tipo incorreto usando notação de ponto, mas o compilador TypeScript não gera um erro de tipo:
database .collection<RecursivePet>("<your collection>") .findOne({ "pet.age": "Spot" });
O trecho de código a seguir faz referência a uma instância de nível superior da interface do RecursivePet
com um tipo incorreto e gera um erro de tipo:
database .collection<RecursivePet>("<your collection>") .findOne({ pet: "Spot" });
O erro criado pelo trecho de código anterior é o seguinte:
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>'.
Se você precisar ter segurança de tipo em instâncias aninhadas de tipos recursivos, você deve escrever sua query ou atualização sem notação de ponto.
Para saber mais sobre notação de pontos, consulte Notação de pontos no manual do MongoDB.
Recursão mútua
Um tipo mutuamente recursivo existe quando dois tipos contêm uma propriedade que é do tipo do outro. Você pode atualizar a interface Pet para que seja mutuamente recursiva, permitindo que um animal de estimação tenha um manipulador e definindo um manipulador para ter um animal de estimação. Os exemplos a seguir referenciam as interfaces Pet
e Handler
mutuamente recursivas:
interface Pet { handler?: Handler; name: string; age: number; } interface Handler { pet: Pet; name: string; }
O driver Node.js fornece segurança de tipo para tipos mutuamente recursivos
referenciados por meio de notação de pontos até uma profundidade de oito. O seguinte trecho de código atribui um string
a um number
e gera um erro de tipo porque a propriedade referenciada está em uma profundidade de quatro:
database .collection<Pet>("<your collection>") .findOne({'handler.pet.handler.pet.age': "four"});
O erro criado pelo trecho de código anterior é o seguinte:
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'.
Em uma profundidade maior ou igual a oito, o TypeScript compila seu código, mas nenhum tipo mais longo o verifica. O código a seguir atribui um string
a uma propriedade number
, mas não causa um erro de compilação porque a propriedade referenciada está em uma profundidade de 10:
database .collection<Pet>("<your collection>") .findOne({'handler.pet.handler.pet.handler.pet.handler.pet.handler.pet.age': "four"});