Conversões de tipos
Todo argumento exportado deve implementar FromNapiValue (ou um dos traits de conversão por referência), e todo valor retornado deve implementar ToNapiValue. O tipo TypeScript gerado é uma documentação útil, mas é a implementação do trait Rust que determina se uma conversão está realmente disponível.
Esta referência descreve o runtime bindgen do napi-rs v3. Para handles de baixo nível, como JsString e JsObject, consulte Env e valores de baixo nível.
Legenda de direção
| Marca | Significado |
|---|---|
| JS → Rust | O tipo pode ser usado como argumento de uma função exportada. |
| Rust → JS | O tipo pode ser retornado ou atribuído a um valor JavaScript. |
| Com escopo | O valor Rust toma emprestado um ambiente Node-API ou um escopo de callback JavaScript e não pode escapar dele. |
| Próprio | A conversão cria ou retém dados de propriedade do Rust que podem sobreviver ao callback, sujeitos às regras de Send do tipo. |
WARNING
Um mapeamento TypeScript não implica que as duas direções de conversão estejam
disponíveis. Por exemplo, u64 gera bigint, mas é somente de saída; use
BigInt ao aceitar um bigint JavaScript arbitrário para poder verificar se
o estreitamento não perdeu dados.
Valores primitivos
| Tipo Rust | JavaScript / TypeScript | Direção | Propriedade e observações | Recurso / Node-API mínimo |
|---|---|---|---|---|
() / Undefined |
undefined; o retorno de uma função se torna void |
Ambas | Marcador de tamanho zero. Com strict, a entrada deve ser undefined. |
API base |
Null |
null |
Ambas | Marcador explícito de null. A conversão de entrada comum aceita e descarta qualquer valor; com strict, a entrada deve ser null. |
API base |
bool |
boolean |
Ambas | Copiado. | API base |
i8, u8, i16, u16, i32, u32 |
number |
Ambas | Conversão de inteiro; o JavaScript ainda armazena um Number. | API base |
f32 |
number |
Rust → JS | É ampliado para um double JavaScript; não há implementação de FromNapiValue. Use f64 na entrada. |
API base |
f64 |
number |
Ambas | O Number do JavaScript usa ponto flutuante IEEE-754 de precisão dupla. | API base |
i64 |
number |
Ambas | Usa a conversão de Number inteiro com sinal de 64 bits do Node-API. Valores fora da faixa de inteiros seguros do JavaScript podem perder precisão. | API base |
BigInt |
bigint |
Ambas | Mantém um bit de sinal e palavras u64 em little-endian. Seus getters informam se o estreitamento não perdeu dados. |
napi6 |
u64, u128, i128, usize, isize, i64n |
bigint |
Rust → JS | Somente saída, para evitar estreitar silenciosamente BigInts JavaScript arbitrários. | napi6 |
String |
string |
Ambas | String UTF-8 própria. | API base |
&str |
string |
Rust → JS | Somente saída Rust emprestada; strings JavaScript não podem ser aceitas como &str. Use String para entrada. |
API base |
Utf16String |
string |
Ambas | Unidades de código UTF-16 próprias; útil quando a representação UTF-16 exata importa. | API base |
Latin1String |
string |
Ambas | Possui bytes Latin-1. Formatá-la como UTF-8 requer latin1. |
API base; latin1 para decodificação/exibição |
OsString, PathBuf |
string |
Ambas | Próprio. O Windows usa UTF-16 e preserva pares substitutos não correspondidos. No Unix, a saída rejeita um caminho não Unicode em vez de substituir bytes. | API base |
&OsStr, &Path |
string |
Rust → JS | Saída emprestada. Mesmas observações de plataforma das formas próprias. | API base |
Symbol |
symbol |
Ambas | A conversão comum de entrada descarta o valor sem reter identidade nem descrição. #[napi(strict)] primeiro valida que ele é um symbol, mas ainda não o retém. Retornar Symbol cria um symbol a partir do estado do descritor Rust. Use JsSymbol com escopo para preservar um valor existente. Symbol::for_desc requer Node-API 9. |
API base; napi9 para symbols globais |
i64 é mapeado deliberadamente para number, enquanto i64n é mapeado para bigint. Prefira o wrapper apenas quando a API JavaScript realmente precisar expor um BigInt.
#[napi]
pub fn inspect_bigint(value: BigInt) -> Result<u64> {
let (negative, narrowed, lossless) = value.get_u64();
if negative || !lossless {
return Err(Error::from_reason("value does not fit in u64"));
}
Ok(narrowed)
}
O tipo de retorno acima é bigint porque u64 é um tipo BigInt de saída.
Option, null e undefined
Option<T> tem um mapeamento intencionalmente assimétrico:
| Posição | JavaScript aceito ou produzido | TypeScript gerado |
|---|---|---|
| Argumento de função | T, null ou undefined; os dois valores nullish se tornam None |
T | null | undefined e normalmente um parâmetro final opcional |
| Retorno de função | Some(T) se torna T; None se torna null |
T | null |
Campo de #[napi(object)] ou forma estruturada com o padrão use_nullable = false |
Ausente ou undefined se torna None; null explícito é passado à conversão de T interno e normalmente falha; None é omitido na saída |
field?: T |
Campo de #[napi(object)] ou forma estruturada com use_nullable = true |
Ausente ou undefined é um erro; null se torna None; None é emitido como null |
field: T | null |
| Campo público de classe | O accessor sempre existe. Um getter de Option emite null para None, e um setter gravável aceita as entradas nullish normais de Option. use_nullable muda a forma gerada da propriedade/construtor, não a existência do accessor. |
Padrão: field?: T; com use_nullable: field: T | null |
Use Null ou Undefined quando a própria distinção fizer parte da API. Use Either<T, Null> ou Either<T, Undefined> quando exatamente um valor nullish for aceito.
#[napi]
pub fn optional_name(value: Option<String>) -> Option<String> {
value.filter(|name| !name.is_empty())
}
#[napi]
pub fn null_but_not_undefined(value: Either<String, Null>) -> bool {
matches!(value, Either::B(Null))
}
INFO
Parâmetros opcionais que não estão no final podem ser emitidos como uniões
obrigatórias, para que um parâmetro obrigatório posterior continue chamável
no TypeScript. A união ainda aceita undefined e null.
Uniões com Either
Either<A, B> até Either26<A, ..., Z> são mapeados para uniões TypeScript. Na entrada, o napi-rs testa as variantes da esquerda para a direita com a implementação de ValidateNapiValue de cada tipo e converte a primeira correspondência.
#[napi]
pub fn normalize_id(value: Either<u32, String>) -> String {
match value {
Either::A(number) => number.to_string(),
Either::B(text) => text,
}
}
export function normalizeId(value: number | string): string
Ordene alternativas sobrepostas da mais específica para a menos específica. A validação de um Object simples, por exemplo, não consegue provar um schema de objeto completo. Either é uma união em tempo de execução, não um enum sem tag no estilo serde com backtracking após código de usuário arbitrário.
Arrays, tuplas, maps e sets
| Tipo Rust | JavaScript / TypeScript | Direção | Comportamento da conversão | Recurso |
|---|---|---|---|---|
Vec<T> |
Array<T> |
Ambas | Copia/converte cada elemento. A entrada exige que cada elemento implemente FromNapiValue. |
API base |
[T; N] |
Array<T> |
Rust → JS | Cria um array JavaScript. | API base |
| Tuplas Rust, até a aridade gerada compatível | Tupla TypeScript / Array JS | Ambas | A entrada deve ter pelo menos o comprimento da tupla; cada elemento indexado é convertido. | API base |
Array<'env> |
unknown[] |
JS → Rust e passagem com escopo | Handle com escopo contendo get, get_ref, set e insert; evita converter o array inteiro antecipadamente. |
API base |
HashMap<K, V>, BTreeMap<K, V> |
Record<K, V> / objeto simples |
Ambas | Usa propriedades próprias, enumeráveis e com chave string. Isto não é um Map JavaScript. As chaves devem poder ser convertidas de/para strings. |
API base |
IndexMap<K, V> |
Record<K, V> / objeto simples |
Ambas | Usa a mesma forma de propriedades próprias, enumeráveis e com chave string, preservando a ordem de inserção Rust quando as regras de propriedade do JavaScript permitem. | object_indexmap |
HashSet<T>, BTreeSet<T> |
Set<T> |
Ambas | Constrói ou itera um Set JavaScript real. |
API base |
IndexSet<T> |
Set<T> |
Ambas | Set Rust com ordem de inserção. | object_indexmap |
A conversão de Vec<T> e coleções é O(n). Use Array, Object, views de typed array com escopo ou um stream quando precisar de acesso incremental, em vez de uma cópia própria.
Objetos, classes e formas personalizadas
| Tipo ou declaração Rust | JavaScript / TypeScript | Direção | Propriedade / identidade |
|---|---|---|---|
Object<'env> |
object |
Ambas dentro do escopo | Handle direto com escopo. Cada acesso a propriedade atravessa o limite do Node-API. |
ObjectRef |
object |
Ambas | Mantém uma referência Node-API para o objeto sobreviver ao callback. |
Unknown<'env> |
unknown |
Ambas dentro do escopo | Handle sem verificação e com escopo; inspecione/converta-o explicitamente. |
#[napi(object)] struct |
Objeto simples / interface | Controlada por object_from_js e object_to_js, ambos habilitados por padrão |
A entrada JavaScript é convertida em uma nova struct Rust própria. Alterá-la não altera o objeto de origem. |
#[napi] struct |
Classe JavaScript | Por referências e instâncias da classe | Preserva a identidade da classe nativa. Os métodos recebem &self/&mut self; campos públicos se tornam acessores. |
ClassInstance<'env, T> |
Uma instância da classe T |
JS → Rust / saída com escopo | Use em campos de objeto ou coleções quando a própria instância da classe JavaScript for necessária. |
#[napi(transparent)] struct Wrapper(T) |
Mesma representação de T |
Controlada por direção | Newtype Rust sem um objeto wrapper JavaScript. |
Struct de tupla #[napi(array)] |
Array JavaScript / tupla TypeScript | Controlada por direção | Tipo Rust nomeado com representação JavaScript posicional. |
#[napi] enum estruturado |
União discriminada de objetos | Controlada por direção | Conversão própria; o discriminador padrão é type. |
Não trate uma classe como uma forma de objeto. Um campo público normal de leitura e escrita precisa de conversão de saída para o getter e de entrada para o setter; um campo readonly precisa apenas de saída, e um campo de classe ignorado não tem accessor. Para valores de classe aninhados, aceite &T, ClassInstance<T> ou use Array::get_ref; Vec<T> exige uma implementação própria de FromNapiValue e, portanto, não é a forma de aceitar uma lista de instâncias de classe.
Consulte Classes, Objetos, Enums e Atributos #[napi] para exemplos específicos de cada forma.
Buffers, ArrayBuffers e typed arrays
| Tipo Rust | JavaScript / TypeScript | Direção | Ciclo de vida e comportamento dos dados | Recurso / Node-API mínimo |
|---|---|---|---|---|
BufferSlice<'env> |
Buffer do Node.js |
Ambas em um escopo síncrono | View mutável emprestada para código síncrono. Não a mantenha durante um await. |
API base |
Buffer |
Buffer do Node.js |
Ambas | Mantém uma referência aos dados pertencentes ao JavaScript e foi projetado para uso assíncrono. Clones referenciam o mesmo buffer subjacente. | Melhor gestão do ciclo de vida com napi4 |
ArrayBuffer<'env> |
ArrayBuffer |
JS → Rust e passagem com escopo | Bytes emprestados e vinculados ao ambiente. | API base |
Int8Array, Uint8Array, … |
Typed array correspondente | Ambas | Wrappers próprios/que retêm referência, adequados para uso assíncrono. | Variantes de array BigInt requerem napi6 |
Int8ArraySlice<'env>, Uint8ArraySlice<'env>, … |
Typed array correspondente | Ambas dentro do escopo | Views emprestadas para código síncrono. | Variantes de array BigInt requerem napi6 |
&[i8], &[u8], &[i16], … |
Typed array correspondente | JS → Rust em um callback síncrono | Slice emprestado; não pode sobreviver ao callback. | Slices BigInt requerem napi6 |
Buffers e ArrayBuffers externos podem ser zero-copy quando o runtime aceita armazenamentos subjacentes externos. Um runtime pode rejeitar buffers externos; construtores como BufferSlice::from_data então recorrem a uma cópia. Não prometa comportamento zero-copy em todo runtime compatível com Node. Consulte Typed arrays e Entendendo o ciclo de vida.
Datas e JSON com serde
| Tipo Rust | JavaScript / TypeScript | Direção | Recurso / observação |
|---|---|---|---|
Date (JsDate) |
Date |
Valor de baixo nível com escopo | napi5 |
chrono::DateTime<Tz>, NaiveDateTime |
Date |
Ambas | chrono_date, que habilita chrono e napi5; a precisão é determinada pelos milissegundos desde a epoch. |
serde_json::Value |
Valor JavaScript compatível com JSON | Ambas | serde-json; rejeita funções, undefined, symbols e valores external. |
serde_json::Map<String, Value> |
Objeto simples | Ambas | serde-json |
serde_json::Number |
Number, BigInt ou string, conforme o valor e a API habilitada | Ambas | serde-json; com napi6, inteiros fora da faixa segura são emitidos como BigInt. |
serde_json::Value não é uma representação sem perdas de JavaScript arbitrário. Em particular, um BigInt de entrada grande pode se tornar um número JSON quando couber ou uma string decimal quando não couber. Use BigInt quando a identidade BigInt e as regras exatas de estreitamento importarem.
serde-json-ordered também habilita o comportamento preserve_order do serde_json.
Funções, Promises e streams
| Tipo Rust | JavaScript / TypeScript | Direção | Ciclo de vida / recurso |
|---|---|---|---|
Function<'env, Args, Return> |
Função JavaScript tipada | JS → Rust no escopo; pode ser repassada no escopo | Chama JavaScript somente na thread à qual pertence. Use FnArgs<(...)> para vários argumentos posicionais. |
FunctionRef<Args, Return> |
Função JavaScript tipada | JS → Rust / referência retida | Possui uma referência Node-API, mas não implementa ToNapiValue. Para devolvê-la, chame borrow_back(env) e obtenha uma Function com escopo; use-a apenas no ambiente/thread ao qual pertence. |
ThreadsafeFunction<...> |
Callback tipado | JS → Rust e depois chamável de outras threads | napi4; consulte ThreadsafeFunction. |
Promise<T> |
Promise<T> |
Somente JS → Rust | Future Rust aguardável. Requer o runtime assíncrono para uso normal em uma exportação async. |
PromiseRaw<'env, T> |
Promise<T> |
Handle de promise JS com escopo | Aceita then, catch e finally sem mover a promise para outra thread. |
Retorno de async fn Rust |
Promise<T> |
Rust → JS | async ou tokio_rt; Result::Err rejeita. |
AsyncTask<T> |
Promise<T::JsValue> |
Rust → JS | Executa compute no pool de workers do libuv. |
ReadableStream<'env, T> |
ReadableStream<T> da Web |
Ambas | web_stream; a construção exige T: Send + 'static e um stream Rust Send + 'static. |
WriteableStream<'env> |
WritableStream da Web |
JS → Rust e passagem com escopo | web_stream; a API Rust atualmente se escreve WriteableStream, e o gerador de tipos não normaliza essa grafia, portanto use ts_arg_type = "WritableStream" em um parâmetro público. |
ReadableStream::new verifica se o runtime fornece um ReadableStream global. Node-API 4 sozinho não garante o global de Web Streams; with_readable_stream_class aceita explicitamente um construtor compatível.
Dados nativos externos
External<T> expõe ao JavaScript uma alocação nativa opaca e com tag de tipo. Ela não é serializada e seu tipo gerado é ExternalObject<T>.
- Retorne um
External<T>próprio para transferi-lo para um valor external JavaScript. - Aceite
&External<T>ou&mut External<T>para tomar emprestado e verificar o tipo do valor encapsulado. - Use
ExternalRef<T>quando o Rust precisar manter uma referência JavaScript para o external. External::new_with_size_hintinforma ao coletor de lixo JavaScript o tamanho da alocação nativa; o número é uma dica contábil para o GC, não um limite de memória.
Consulte External para detalhes do ciclo de vida.
Validação não é coerção
A maioria das funções geradas converte de acordo com sua implementação de FromNapiValue. Adicionar #[napi(strict)] primeiro chama ValidateNapiValue e rejeita um tipo JavaScript incompatível no nível superior. Isso não converte strings em números nem valida recursivamente cada propriedade antes da conversão.
#[napi(return_if_invalid)] faz a mesma validação, mas retorna undefined para uma entrada inválida em vez de lançar uma exceção. Consulte Atributos #[napi] para conhecer suas restrições.
Escolhendo um modelo de propriedade
Use esta ordem de preferência:
- Use valores Rust próprios (
String,Vec<T>,#[napi(object)]) quando uma cópia for aceitável e o valor precisar atravessar threads ou pontos de await. - Use handles e slices com escopo (
Object<'env>,Array<'env>,BufferSlice<'env>, slices de typed array) para acesso síncrono com zero ou poucas cópias. - Use wrappers que retêm referências (
Buffer,ObjectRef,FunctionRef,Reference<T>) quando dados pertencentes ao JavaScript precisarem sobreviver ao callback. - Use
ThreadsafeFunctionpara invocar JavaScript de outra thread; nunca mova para lá um handle JavaScript com escopo. - Use um stream quando os dados precisarem ser produzidos de forma incremental, em vez de copiados para uma única coleção.
O compilador impõe muitos desses limites por meio de lifetimes e Send, mas um método unsafe ou handle bruto do Node-API pode ignorá-los. Leia Entendendo o ciclo de vida antes de fazer isso.