Skip to content

Data Unit Converter — JavaScript source

Convert between digital data units - B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. Switch between decimal (1000) and binary (1024) bases, runs entirely in your browser.

This is the JavaScript implementation — the same logic the interactive tool runs, in a shareable, citable form.

// data-unit-converter - polyglot showcase port (JavaScript).
//
// Pure digital-data unit conversion for the Data Unit Converter tool on
// CosmoDev (dev.cosmolabs.org). Ported from the canonical TypeScript source at
// src/lib/dataUnits.ts so the tool page can display the same logic across six
// languages.
//
// Supports B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. Decimal base = 1000 (KB, MB, GB,
// TB); binary base = 1024 (KiB, MiB, GiB, TiB). Pure + deterministic - the
// unit-test surface. Never throws: non-finite values or unknown units yield NaN.
//
// Self-contained: standard library only, no external dependencies.
//
// License/usage: display source - part of CosmoDev's polyglot tool pages.

'use strict';

/**
 * Supported conversion bases: 1000 (decimal/SI) or 1024 (binary/IEC).
 * @typedef {1000 | 1024} DataBase
 */

/**
 * Recognized digital-data units. The 'K/M/G/T' family is decimal (1000); the
 * 'Ki/Mi/Gi/Ti' family is binary (1024); 'B' (bytes) is shared by both.
 * @typedef {'B'|'KB'|'MB'|'GB'|'TB'|'KiB'|'MiB'|'GiB'|'TiB'} DataUnit
 */

/**
 * Units available under each base, ordered smallest (B) to largest. Used by the
 * UI to populate the per-base unit pickers.
 * @type {Record<1000 | 1024, DataUnit[]>}
 */
const UNITS = {
  1000: ['B', 'KB', 'MB', 'GB', 'TB'],
  1024: ['B', 'KiB', 'MiB', 'GiB', 'TiB'],
};

// Power-of-base rank for each unit: B is rank 0, each prefix step adds 1.
// KB and KiB are both rank 1 - the *unit* decides the divisor, the *base*
// decides whether one rank means ×1000 or ×1024.
const EXPONENT = {
  B: 0,
  KB: 1, MB: 2, GB: 3, TB: 4,
  KiB: 1, MiB: 2, GiB: 3, TiB: 4,
};

/**
 * Convert a value between two digital-data units under the given base.
 *
 * Strategy: reduce to bytes via value × base^fromExp, then divide by
 * base^toExp. Returns NaN for non-finite input, unknown units, or an invalid
 * base - never throws (mirrors the TypeScript contract).
 *
 * @param {number} value    - Magnitude to convert.
 * @param {DataUnit} fromUnit - Source unit symbol.
 * @param {DataUnit} toUnit   - Target unit symbol.
 * @param {DataBase} base     - Conversion base (1000 or 1024).
 * @returns {number} Converted value, or NaN on invalid input.
 */
function convertData(value, fromUnit, toUnit, base) {
  // Guard non-finite numbers first - Infinity/NaN propagate no further.
  if (!Number.isFinite(value)) return NaN;
  // Only the two canonical bases are valid; anything else is a caller bug.
  if (base !== 1000 && base !== 1024) return NaN;

  const fromExp = EXPONENT[fromUnit];
  const toExp = EXPONENT[toUnit];
  // Unknown unit symbols index into `undefined`; treat as invalid.
  if (fromExp === undefined || toExp === undefined) return NaN;

  return (value * base ** fromExp) / base ** toExp;
}

// --- CommonJS exports so the snippet can also be require()'d in Node -------
if (typeof module !== 'undefined' && module.exports) {
  module.exports = { UNITS, convertData };
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →