npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@zerovoids/utils

v2.0.0

Published

Type-safe utility library for number formatting, unit conversion, and precision rounding

Downloads

182

Readme

@zerovoids/utils

Modern utility library for TypeScript

npm version npm downloads codecov license

FeaturesInstallationModulesDocumentation


✨ Features

  • 🎯 Type-Safe - Full TypeScript support with comprehensive type definitions
  • 📦 Tree-Shakable - Import only what you need, optimized bundle size
  • 🔄 Dual Package - Works seamlessly with both ESM and CommonJS
  • ⚡ Zero Dependencies - Lightweight with no external dependencies
  • ✅ Well Tested - Comprehensive test coverage with Vitest
  • 🎨 Modern Codebase - Built with the latest JavaScript features

📦 Installation

# npm
npm install @zerovoids/utils

# pnpm
pnpm add @zerovoids/utils

# yarn
yarn add @zerovoids/utils

🆙 Migrating to v2

  • toBankersRoundbankersRound
  • roundHalfAwayFromZerohalfAwayFromZero
  • bankersRound no longer auto-promotes precision for |value| < 1. The caller's precision is always respected as-is. If you need the old adaptive behavior, use formatNumber(v, { mode: "adaptive", roundMethod: "bankersRound" }).
  • BaseUnit no longer contains the "custom" slot — define your own via UnitMap<"your-category"> when you need identity behavior.
  • The package root now re-exports flatly, so import { formatNumber } from "@zerovoids/utils" works directly (no more number.formatNumber(...) namespace).
  • getSignificantDigitIndex is no longer part of the public API.

📚 Modules

📊 Number Utils

Advanced number formatting and precision rounding utilities.

import { formatNumber, bankersRound, halfAwayFromZero } from '@zerovoids/utils/number';

// Adaptive formatting - perfect for charts and visualizations
formatNumber(0.0000345, { mode: 'adaptive', decimals: 2 });
// → "0.00003"

formatNumber(1234.5678, { mode: 'adaptive', decimals: 2 });
// → "1,234.57"

// Fixed decimal places with custom affixes
formatNumber(1234567.89, {
  mode: 'fixed',
  decimals: 2,
  prefix: { text: '$', space: false },
  suffix: { text: 'USD', space: true },
});
// → "$1,234,567.89 USD"

// Native compact notation
formatNumber(1_234_000, { mode: 'compact' });
// → "1.23M"

// Negative sign before the prefix
formatNumber(-1234.5, {
  decimals: 2,
  prefix: '$',
  signPosition: 'before-prefix',
});
// → "-$1,234.50"

// Safe handling of NaN / ±Infinity
formatNumber(Number.NaN, { nonFinite: '-' });
// → "-"

// Banker's rounding (IEEE 754) - reduces cumulative rounding bias
bankersRound(2.5, { precision: 0 }); // → 2 (rounds to even)
bankersRound(3.5, { precision: 0 }); // → 4 (rounds to even)

// Commercial rounding (round half away from zero)
halfAwayFromZero(2.5, { precision: 0 });  // → 3
halfAwayFromZero(-2.5, { precision: 0 }); // → -3

Features:

  • Multiple formatting modes: adaptive, fixed, auto, raw, compact
  • Precision rounding methods: banker's round, commercial round
  • Customizable prefixes and suffixes with spacing + sign placement control
  • Locale-aware number formatting
  • Graceful NaN / ±Infinity fallback via nonFinite

⚡ Unit Conversion

Flexible unit conversion utilities optimized for data visualization and dashboards.

import {
  convertUnitFromTo,
  convertUnitToFit,
  getOptimalUnit,
} from '@zerovoids/utils/unit';

// Direct unit conversion
convertUnitFromTo({
  number: 5000,
  unit: 'mass',
  from: 'g',
  to: 'kg',
});
// → { number: 5, unit: 'mass', suffix: 'kg' }

// Auto-fit to most appropriate unit
convertUnitToFit({
  number: 500,
  unit: 'mass',
  from: 'g',
});
// → { number: 500, unit: 'mass', suffix: 'g' }

convertUnitToFit({
  number: 5000,
  unit: 'mass',
  from: 'g',
});
// → { number: 5, unit: 'mass', suffix: 'kg' }

// `saturated` flags when the scan hit the end of the suffix list
convertUnitToFit({ number: 9e15, unit: 'mass', from: 'g' });
// → { number: 9e6, unit: 'mass', suffix: 'ton', saturated: 'max' }

// Find optimal unit for multiple values (perfect for charts)
getOptimalUnit({ numbers: [500, 1500, 2500], unit: 'mass', from: 'g' });
// → 'g'

getOptimalUnit({ numbers: [5000, 15000, 25000], unit: 'mass', from: 'g' });
// → 'kg'

Built-in Units:

  • Mass: g, kg, ton (gap: 3 → 1000× between units)
  • Area: cm², m², km² (gap: 6 → 1,000,000× between units)
  • Volume: mL, L, kL (gap: 3 → 1000× between units)
  • Data: B, KB, MB, GB, TB, PB (gap: 3 → 1000× between units)
  • Count: "", K, M, B, T (gap: 3 → 1000× between units, for large numbers like 5K, 2.5M)

Custom Units:

import { convertUnitToFit, type UnitMap } from '@zerovoids/utils/unit';

const energyMap: UnitMap<'energy' | 'temperature'> = {
  energy: { gap: 3, suffices: ['Wh', 'kWh', 'MWh', 'GWh'], baseIndex: 1 },
  temperature: { gap: 3, suffices: ['mK', 'K', 'kK'], baseIndex: 1 },
};

convertUnitToFit({
  number: 5000,
  unit: 'energy',
  from: 'Wh',
  unitMap: energyMap,
});
// → { number: 5, unit: 'energy', suffix: 'kWh' }

Features:

  • Smart auto-conversion to optimal units
  • Consistent unit selection for chart datasets
  • Fully customizable unit mappings
  • Precision handling with pluggable roundMethod
  • Support for various optimization strategies (min, max, freq)

🎯 Why @zerovoids/utils?

Unlike general-purpose libraries (lodash, ramda), @zerovoids/utils provides specialized utilities that solve specific problems:

| Problem | Solution | |---------|----------| | Chart numbers with varying magnitudes | formatNumber with adaptive mode | | Financial calculations with rounding bias | bankersRound (IEEE 754) | | Dashboard unit consistency | Smart unit conversion with getOptimalUnit | | File size formatting | Built-in data units (B, KB, MB, GB, etc.) | | Large number abbreviations | compact mode or count units (K, M, B, T) |


🎨 Usage Examples

Chart Data Formatting

import { formatNumber } from '@zerovoids/utils/number';

const chartData = [0.00012, 1.5, 1234.567, 999999];

const formatted = chartData.map((value) =>
  formatNumber(value, { mode: 'adaptive', decimals: 2 }),
);
// → ["0.00012", "1.5", "1,234.57", "999,999"]

Weight Dashboard

import {
  convertUnitFromTo,
  convertUnitToFit,
  getOptimalUnit,
} from '@zerovoids/utils/unit';

// Auto-convert individual values
const weight = convertUnitToFit({
  number: 5420,
  unit: 'mass',
  from: 'g',
});
// → { number: 5.42, unit: 'mass', suffix: 'kg' }

// Find optimal unit for chart axis
const chartValues = [4500, 8200, 12000, 15800];
const optimalUnit = getOptimalUnit({
  numbers: chartValues,
  unit: 'mass',
  from: 'g',
});
// → 'kg'

// Convert all values to optimal unit
const chartData = chartValues.map((value) =>
  convertUnitFromTo({
    number: value,
    unit: 'mass',
    from: 'g',
    to: optimalUnit,
  }),
);
// → All values converted to kg for consistent display

File Size Formatting

import { convertUnitToFit } from '@zerovoids/utils/unit';

const fileSizes = [1024, 1048576, 1073741824];

const formatted = fileSizes.map((bytes) =>
  convertUnitToFit({ number: bytes, unit: 'data', from: 'B' }),
);
// → [
//   { number: 1.024, unit: 'data', suffix: 'KB' },
//   { number: 1.049, unit: 'data', suffix: 'MB' },
//   { number: 1.074, unit: 'data', suffix: 'GB' }
// ]

Large Number Abbreviation

import { formatNumber } from '@zerovoids/utils/number';

formatNumber(2_547_893, { mode: 'compact', decimals: 1 });
// → "2.5M"

📖 Documentation

Detailed API documentation is coming soon.


🛠️ Development

# Install dependencies
pnpm install

# Run tests
pnpm test

# Run tests in watch mode
pnpm test:watch

# Build
pnpm build

# Lint and format
pnpm check

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.


📄 License

MIT © zerovoids


🔗 Links


Made with ❤️ by zerovoids