Uint8Array.toBase64() e fromBase64(): adeus ao btoa/atob

Conheça os novos métodos nativos toBase64(), fromBase64(), setFromBase64(), toHex() e fromHex() do Uint8Array, que substituem os rodeios frágeis de btoa()/atob() para converter bytes binários em texto.

Converter bytes binários em texto e vice-versa sempre exigiu rodeios em JavaScript: btoa() e atob() trabalham com strings, não com bytes, então codificar um Uint8Array em base64 significava passar por uma string intermediária cheia de armadilhas com Unicode. O TC39 resolveu isso com um conjunto de métodos nativos direto no Uint8Array: toBase64(), fromBase64(), setFromBase64() e os equivalentes em hexadecimal, toHex() e fromHex().

O jeito antigo, e por que ele quebrava

Antes desses métodos, converter bytes para base64 passava por String.fromCharCode byte a byte antes de chamar btoa():

const bytes = new Uint8Array([72, 101, 108, 108, 111]);

let binario = '';
for (const byte of bytes) {
    binario += String.fromCharCode(byte);
}

const base64 = btoa(binario);
console.log(base64); // "SGVsbG8="

Funciona para bytes simples, mas btoa() lança uma exceção se algum "caractere" do binário ficar fora da faixa Latin1 (0-255) — o que acontece com facilidade quando o array vem de operações que geram valores fora dessa faixa por engano. É um código verboso, lento em arrays grandes e fácil de errar.

toBase64() e fromBase64()

Agora a conversão é direta, sem strings intermediárias:

const bytes = new Uint8Array([72, 101, 108, 108, 111]);

const base64 = bytes.toBase64();
console.log(base64); // "SGVsbG8="

const devolta = Uint8Array.fromBase64(base64);
console.log(devolta); // Uint8Array(5) [72, 101, 108, 108, 111]

toBase64() é um método de instância — chamado no array que você já tem. fromBase64() é estático, chamado direto em Uint8Array, e devolve um array novo a partir da string.

Base64 seguro para URL

O alfabeto padrão usa + e /, que precisam de escape em URLs e nomes de arquivo. Um objeto de opções com alphabet: "base64url" troca esses caracteres por - e _, e omitPadding remove o = do final:

const id = new Uint8Array([250, 208, 15, 3]);

const token = id.toBase64({ alphabet: 'base64url', omitPadding: true });
console.log(token); // pronto para ir direto numa URL, sem encodeURIComponent

const restaurado = Uint8Array.fromBase64(token, { alphabet: 'base64url' });

É importante passar as mesmas opções na decodificação: uma string gerada com base64url não decodifica corretamente com o alfabeto padrão.

setFromBase64(): decodificando em um buffer existente

Quando você já tem um Uint8Array alocado (por exemplo, uma view sobre um ArrayBuffer reaproveitado) e quer preencher parte dele sem criar um array novo, setFromBase64() escreve os bytes decodificados diretamente nele:

const destino = new Uint8Array(16);

const { read, written } = destino.setFromBase64('SGVsbG8=');

console.log(written); // 5 — bytes escritos em destino
console.log(destino.subarray(0, written)); // Uint8Array(5) [72, 101, 108, 108, 111]

O retorno traz read (quantos caracteres da string foram consumidos) e written (quantos bytes foram gravados), úteis quando o buffer é maior que os dados decodificados.

toHex() e fromHex()

Para quem precisa de uma representação legível byte a byte, como hashes e checksums, os mesmos métodos existem para hexadecimal:

const hash = new Uint8Array([255, 0, 171, 16]);

console.log(hash.toHex()); // "ff00ab10"

const bytes = Uint8Array.fromHex('ff00ab10');
console.log(bytes); // Uint8Array(4) [255, 0, 171, 16]

Quando usar

Cuidado com o resultado de crypto.subtle.digest()

Funções como crypto.subtle.digest() devolvem um ArrayBuffer, não um Uint8Array diretamente. É preciso envolver o resultado antes de chamar os novos métodos:

const dados = new TextEncoder().encode('minha senha');
const digest = await crypto.subtle.digest('SHA-256', dados);

const hex = new Uint8Array(digest).toHex();
console.log(hex); // hash em hexadecimal, pronto para comparar ou salvar

Compatibilidade

Esses métodos fazem parte de uma proposta do TC39 que chegou a Stage 4 e já tem suporte nos navegadores modernos e no Node.js recente desde 2025. Como é uma adição bem nova, vale checar o suporte antes de depender dela em produção, ou usar um polyfill para ambientes mais antigos.

caniuse

Conclusão

Com toBase64(), fromBase64(), setFromBase64() e os equivalentes em hexadecimal, o JavaScript finalmente trata a conversão entre bytes e texto como uma operação de primeira classe, sem os rodeios frágeis de btoa/atob e sem depender de bibliotecas externas só para essa tarefa.

Tecnologia:
js

Deixe seu Comentário!

Dúvida, sugestão ou só um "valeu!" — tudo é bem-vindo por aqui.

Comentário
Nome
Email
lock Seu e-mail não será publicado.