Base64 Encoding & Decoding in TypeScript
TypeScript doesn't add new Base64 APIs — it runs the same JavaScript under the hood. But types let you build robust, reusable utilities. Here are production-ready, typed Base64 helpers for browser and Node.js.
Browser: Typed btoa / atob Wrappers
// base64.ts — browser-compatible, Unicode-safe
/**
* Encode a Unicode string to Base64.
* Uses TextEncoder for correct UTF-8 handling.
*/
export function encodeBase64(input: string): string {
const bytes = new TextEncoder().encode(input);
let binary = '';
bytes.forEach(byte => { binary += String.fromCharCode(byte); });
return btoa(binary);
}
/**
* Decode a Base64 string to Unicode text.
* Returns null if the input is invalid Base64.
*/
export function decodeBase64(input: string): string | null {
try {
const binary = atob(input);
const bytes = Uint8Array.from(binary, c => c.charCodeAt(0));
return new TextDecoder().decode(bytes);
} catch {
return null;
}
}
/**
* Encode a string to URL-safe Base64 (no padding).
*/
export function encodeBase64URL(input: string): string {
return encodeBase64(input)
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
}
/**
* Decode a URL-safe Base64 string.
*/
export function decodeBase64URL(input: string): string | null {
let base64 = input.replace(/-/g, '+').replace(/_/g, '/');
while (base64.length % 4) base64 += '=';
return decodeBase64(base64);
}
Node.js: Buffer-Based Utilities
// base64-node.ts — Node.js only
import { Buffer } from 'buffer';
export function encodeBase64(input: string | Buffer): string {
const buf = typeof input === 'string' ? Buffer.from(input, 'utf8') : input;
return buf.toString('base64');
}
export function decodeBase64(input: string): string {
return Buffer.from(input, 'base64').toString('utf8');
}
export function encodeBase64URL(input: string | Buffer): string {
const buf = typeof input === 'string' ? Buffer.from(input, 'utf8') : input;
return buf.toString('base64url'); // Node 16+
}
export function decodeBase64URL(input: string): Buffer {
return Buffer.from(input, 'base64url'); // Node 16+
}
// Encode a file
import { readFileSync, writeFileSync } from 'fs';
export function encodeFile(path: string): string {
return readFileSync(path).toString('base64');
}
export function decodeToFile(encoded: string, outputPath: string): void {
writeFileSync(outputPath, Buffer.from(encoded, 'base64'));
}
Universal (Browser + Node.js)
For libraries or packages that must work in both environments:
// base64-universal.ts
function isNode(): boolean {
return typeof process !== 'undefined' && !!process.versions?.node;
}
export function encodeBase64(input: string): string {
if (isNode()) {
return Buffer.from(input, 'utf8').toString('base64');
}
// Browser path
const bytes = new TextEncoder().encode(input);
let binary = '';
bytes.forEach(b => { binary += String.fromCharCode(b); });
return btoa(binary);
}
export function decodeBase64(input: string): string {
if (isNode()) {
return Buffer.from(input, 'base64').toString('utf8');
}
const binary = atob(input);
const bytes = Uint8Array.from(binary, c => c.charCodeAt(0));
return new TextDecoder().decode(bytes);
}
Typed Data URI Helper
interface DataURI {
mimeType: string;
encoding: 'base64';
data: string;
toString(): string;
}
export function parseDataURI(uri: string): DataURI | null {
const match = uri.match(/^data:([^;]+);base64,(.+)$/);
if (!match) return null;
return {
mimeType: match[1],
encoding: 'base64',
data: match[2],
toString: () => uri,
};
}
export function buildDataURI(mimeType: string, base64Data: string): string {
return `data:${mimeType};base64,${base64Data}`;
}
Zod Validation for Base64 Fields
import { z } from 'zod';
const Base64Schema = z.string().refine(
(s) => {
try { atob(s); return true; } catch { return false; }
},
{ message: 'Invalid Base64 string' }
);
// Usage in API schema
const UploadSchema = z.object({
filename: z.string(),
content: Base64Schema,
mimeType: z.string(),
});
Test your TypeScript Base64 output
Paste encoded strings from your TypeScript code into base64.dev to inspect and decode them.
Open base64.dev →