New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

ts-measurements

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ts-measurements

A comprehensive, modern TypeScript library for handling measurements, units, and conversions with type safety and precision.

latest
npmnpm
Version
1.3.1
Version published
Weekly downloads
0
Maintainers
1
Weekly downloads
 
Created
Source

TypeScript Units Library

A comprehensive, modern TypeScript library for handling measurements, units, and conversions with type safety and precision.

Features

  • Type-Safe Unit Conversions: Prevent mixing incompatible units with TypeScript's type system.
  • Comprehensive Unit Coverage: Length, weight, temperature, time, angle, velocity, energy, and more.
  • Fluent API: Intuitive method chaining for natural, readable code.
  • Flexible Creation Options: Create measurements using constructor, constants, or parse from strings like "100ft/s".
  • Precision Control: Customize decimal places, rounding methods, and formatting for display.
  • Unit Aliases: Supports alternative symbols for units (e.g., "mi/h" for "mph") and preserves user-inputted symbols in outputs.
  • Detailed Error Messages: Clear error messages when using unsupported units.

Installation

npm install ts-measurements

Basic Usage

Key Concepts

Creating Measurements

You can create Measurement instances in several primary ways:

1. Using Value and Unit Symbol (String)

Provide the numeric value and the unit as a string symbol directly to the constructor.

import { Measurement, UnitCategory } from 'ts-measurements';

// Create a measurement using a string symbol for the unit
const distance = new Measurement(100, 'm'); // 100 meters
console.log(distance.toString({ includeUnit: true })); // "100.0000 m" (default precision)

// For type-specific functions, provide the category
const weight = new Measurement<UnitCategory.Weight>(70.5, 'kg'); // 70.5 kilograms
console.log(weight.toString({ decimals: 1, includeUnit: true })); // "70.5 kg"
2. Using an Object Literal (MeasurementData)

You can also construct a Measurement using an object literal that conforms to the MeasurementData interface ({ value: number; unit: string; }).

import { Measurement, UnitCategory, MeasurementData } from 'ts-measurements';

const lengthData: MeasurementData = { value: 25, unit: 'cm' };
const myLength = new Measurement<UnitCategory.Length>(lengthData);
console.log(myLength.toString({ includeUnit: true })); // "25.0000 cm"

// Inline object literal
const speed = new Measurement<UnitCategory.Velocity>({ value: 60, unit: 'km/h' });
console.log(speed.toString({ includeUnit: true })); // "60.0000 km/h"
3. Using the fromString Static Method

Parse a string that contains both the value and unit in a single expression:

import { Measurement } from 'ts-measurements';

// Create measurements directly from strings
const velocity = Measurement.fromString('100ft/s');
console.log(velocity.toString({ includeUnit: true })); // "100.0000 ft/s"

// The method handles spaces between value and unit
const anotherLength = Measurement.fromString('10 m');
console.log(anotherLength.toString({ includeUnit: true })); // "10.0000 m"

// Works with negative values and compound units
const temperatureFromString = Measurement.fromString('-273.15°C');
console.log(temperatureFromString.toString({ includeUnit: true })); // "-273.1500 °C"
4. Using Units Constants

For enhanced type safety and discoverability, you can use the exported Units constants.

import { Measurement, Units } from 'ts-measurements';

// Create a measurement using a Units constant
const temperature = new Measurement(25, Units.Temperature.CELSIUS); // 25 degrees Celsius
console.log(temperature.toString({ includeUnit: true })); // "25.0000 °C"

const duration = new Measurement(2, Units.Time.HOUR); // 2 hours
console.log(duration.toString({ decimals: 0, includeUnit: true })); // "2 h"
5. Using Unit Aliases

The library supports alternative symbols (aliases) for units. When you create a measurement using an alias, the library recognizes it and correctly maps it to its canonical unit. Furthermore, methods like toString(), toData(), and toJSON() will use the original symbol (alias or canonical) that you provided.

import { Measurement } from 'ts-measurements';

// Using an alias for miles per hour
const speedMih = new Measurement(60, 'mi/h');
console.log(speedMih.toString({ includeUnit: true })); // "60.0000 mi/h"
console.log(speedMih.unit.symbol); // "mph" (canonical symbol is still accessible)
console.log(speedMih.originalSymbol); // "mi/h" (the alias used)

// Using an alias for feet per second
const fallSpeed = Measurement.fromString('32 fps');
console.log(fallSpeed.toString({ includeUnit: true })); // "32.0000 fps"
console.log(fallSpeed.unit.symbol); // "ft/s"
console.log(fallSpeed.originalSymbol); // "fps"

// Using an alias for foot-pounds
const workDone = new Measurement(100, 'ft-lb');
console.log(workDone.toString({ includeUnit: true })); // "100.0000 ft-lb"
console.log(workDone.unit.symbol); // "ft⋅lb" (canonical uses a middle dot)
console.log(workDone.originalSymbol); // "ft-lb"

This flexibility allows users to input units in formats they are most familiar with, while the library maintains consistent internal handling.

For creating measurements intended for functions that require a specific unit category, see the "Type-Specific Measurement Functions" section under "Advanced Features".

Unit Conversions & Data Extraction

The Measurement class offers methods for unit conversion and extracting data:

  • convert(toUnitOrString: (Unit & { category: C }) | string): Returns a new Measurement instance representing the value in the target unit. This is useful for chaining further Measurement operations.
  • toData(): MeasurementData: Returns a plain JavaScript object conforming to the MeasurementData interface ({ value: number, unit: string }) containing the measurement's current value and the original unit symbol (or alias) used during creation. This is the recommended way to get a simple object representation that preserves user input.
  • to(unitIdentifier: string): { value: number, unit: string }: (Legacy) Converts the measurement to another unit and returns a plain JavaScript object { value: number, unit: string }. The unit in the returned object will be the unitIdentifier you passed in (which could be an alias or canonical symbol). While functional, convert() followed by toData() or directly using toData() on the original measurement is generally preferred for clarity and consistency.
import { Measurement, Units, MeasurementData } from 'ts-measurements';

const length = new Measurement(5, 'm');

// Using convert() -> returns a new Measurement instance
const lengthInFtMeasurement = length.convert('ft');
console.log(lengthInFtMeasurement.toString({ decimals: 2, includeUnit: true })); // "16.40 ft"
// Further operations can be chained
console.log(lengthInFtMeasurement.multiply(2).toString({ decimals: 2, includeUnit: true })); // "32.81 ft"

// Using toData() -> returns a MeasurementData object { value, unit }
const currentLengthData: MeasurementData = length.toData();
console.log(currentLengthData); // { value: 5, unit: 'm' } (assuming 'm' was the original input)

// Using to() -> returns a { value, unit } object after conversion
const lengthInFtObject = length.to('ft');
console.log(lengthInFtObject); // { value: 16.404199475065616, unit: 'ft' } (unit will be 'ft' as passed to to())
console.log(lengthInFtObject.value * 2); // 32.80839895013123 (Direct access to the numerical value)

Arithmetic Operations

Measurement instances support arithmetic operations. Operations like add and subtract will automatically handle unit conversions if the measurements are of the same category but different units.

import { Measurement, Units } from 'ts-measurements';

const initialDistance = new Measurement(10, 'km');
const addedDistance = new Measurement(500, 'm');

// Add (converts 'm' to 'km' internally for the operation, result in 'km')
const totalDistance = initialDistance.add(addedDistance);
console.log(totalDistance.toString({ includeUnit: true })); // "10.5000 km"

// Subtract
const remainingDistance = totalDistance.subtract(new Measurement(1.2, 'km'));
console.log(remainingDistance.toString({ includeUnit: true })); // "9.3000 km"

// Multiply by a scalar
const doubledDistance = initialDistance.multiply(2);
console.log(doubledDistance.toString({ includeUnit: true })); // "20.0000 km"

// Divide by a scalar
const halfDistance = initialDistance.divide(2);
console.log(halfDistance.toString({ includeUnit: true })); // "5.0000 km"

Advanced Features

Precision Control & Formatting with toString()

The Measurement.toString(options?: FormatOptions) method allows for detailed control over the string representation of a measurement. You can specify decimal places, rounding methods, inclusion of the unit symbol, and number formatting.

import { Measurement, Units, FormatOptions } from 'ts-measurements';

const largeDistance = new Measurement(1234567.89123, Units.Length.KILOMETER);

// Default formatting (usually 4 decimal places, no unit by default from toString())
console.log(largeDistance.toString()); // "1234567.8912"

// Basic precision control (decimal places) and include unit
console.log(largeDistance.toString({ decimals: 0, includeUnit: true })); // "1234568 km"
console.log(largeDistance.toString({ decimals: 3, includeUnit: true })); // "1234567.891 km"

// Control rounding method
const optionsFloor: FormatOptions = { decimals: 1, rounding: 'floor', includeUnit: true };
console.log(largeDistance.toString(optionsFloor)); // "1234567.8 km"

const optionsCeil: FormatOptions = { decimals: 1, rounding: 'ceil', includeUnit: true };
console.log(largeDistance.toString(optionsCeil)); // "1234567.9 km"

// Format with thousands separator
const optionsThousands: FormatOptions = { thousands: true, decimals: 2, includeUnit: true };
console.log(largeDistance.toString(optionsThousands)); // "1,234,567.89 km"

// International formatting (e.g., German style)
const optionsInternational: FormatOptions = {
  thousands: true,
  thousandsSeparator: '.',
  decimalSeparator: ',',
  decimals: 2,
  includeUnit: true
};
console.log(largeDistance.toString(optionsInternational)); // "1.234.567,89 km"

// Trailing zeros
console.log(new Measurement(10, 'm').toString({ decimals: 3, trailingZeros: true, includeUnit: true })); // "10.000 m"
console.log(new Measurement(10.12, 'm').toString({ decimals: 3, trailingZeros: true, includeUnit: true })); // "10.120 m"
console.log(new Measurement(10.12, 'm').toString({ decimals: 3, trailingZeros: false, includeUnit: true })); // "10.12 m" (if no trailing zeros needed)

See FormatOptions in the API Reference for all available formatting options.

Type-Specific Measurement Functions

To create functions that only accept Measurement instances of a specific category (e.g., only pressure measurements), you can explicitly provide the unit category as a generic type argument when creating the Measurement. This leverages TypeScript's generics to enforce type safety at compile time.

import { Measurement, Units, UnitCategory } from 'ts-measurements';

// Define a function that only accepts Pressure measurements
function getPressureInPascals(pressureMeasurement: Measurement<UnitCategory.Pressure>): number {
  // This function will only compile if pressureMeasurement is of type Measurement<UnitCategory.Pressure>
  return pressureMeasurement.to(Units.Pressure.PASCAL).value;
}

// Create a pressure measurement with an explicit category type
const oilPressure = new Measurement<UnitCategory.Pressure>(35, Units.Pressure.PSI);
const atmosphericPressure = new Measurement<UnitCategory.Pressure>(1, Units.Pressure.ATMOSPHERE);

// These calls are type-safe and will compile
console.log(getPressureInPascals(oilPressure));
console.log(getPressureInPascals(atmosphericPressure));

// Create a length measurement
const cableLength = new Measurement<UnitCategory.Length>(10, Units.Length.METER);

// The following line would cause a TypeScript compilation error,
// because Measurement<UnitCategory.Length> is not assignable to Measurement<UnitCategory.Pressure>.
// getPressureInPascals(cableLength); // Compile-time error!

This pattern is useful for ensuring that functions operating on specific physical quantities receive only appropriate measurement types.

Error Handling

When attempting to use an unsupported unit or convert between incompatible categories, the library provides detailed error messages.

import { Measurement } from 'ts-measurements';

try {
  // Attempt to use an unsupported unit
  const distance = new Measurement(100, 'lightyears'); // 'lightyears' is not a defined unit symbol
} catch (error: any) {
  console.error(error.message);
  // Example Output: "Unit not found in registry: 'lightyears'"
}

try {
  const length = new Measurement(10, 'm');
  length.convert('kg'); // Cannot convert meters (length) to kilograms (weight)
} catch (error: any) {
  console.error(error.message);
  // Example Output: "Cannot convert between different categories: length and weight"
}

Available Units

The library supports a wide range of units across various categories:

CategoryUnits
Lengthm, km, cm, mm, in, ft, yd, mi
Weightkg, g, mg, lb, oz, grain
Temperature°C, °F, K
Times, min, h, d, wk, ms, μs
Anglerad, °, grad, moa, mrad, iphy, cphm
EnergyJ, kJ, ft⋅lb, cal, kcal, BTU, kWh
Velocitym/s, km/h, mph, kn, ft/s
PressurePa, bar, mbar, mmHg, inHg, psi, atm
Densitykg/m3, lb/ft3
Percentage%
BallisticCoefficientG1, G2, G5, G6, G7, G8, GI, GS, GC

Note: The Percentage and BallisticCoefficient unit categories are unique in that they do not support conversions to other units. Any attempt to convert them will result in an error.

API Reference

Core Classes

  • Measurement<C extends UnitCategory>: Class representing a value with an associated unit. C is a type parameter representing a specific member of the UnitCategory enum (e.g., UnitCategory.Length, UnitCategory.Pressure).

    • constructor(value: number, unitIdentifier: string): Creates a new measurement using a numeric value and a unit identifier string (symbol or name).
    • constructor(data: MeasurementData): Creates a new measurement from an object conforming to the MeasurementData interface ({ value: number; unit: string; }).
    • static fromString<C extends UnitCategory>(input: string): Measurement<C>: Static factory method that creates a Measurement instance from a string containing both the value and unit (e.g., "100ft/s", "10 m", "-273.15°C").
    • unit: Unit & { category: C }: The resolved canonical unit object for this measurement. Its category property will be of the specific type C.
    • originalSymbol: string: The original unit symbol or alias string used when the measurement was created.
    • value: number: The numerical value of this measurement.
    • convert(toUnitOrString: (Unit & { category: C }) | string): Measurement<C>: Converts the measurement to a different unit within the same category, returning a new Measurement instance. The new instance's originalSymbol will be the toUnitOrString identifier.
    • toData(): MeasurementData: Returns a plain object representation ({ value: number; unit: string; }) of the measurement's current value and its originalSymbol.
    • to(toUnitIdentifier: string): { value: number; unit: string }: (Legacy) Converts the measurement to a different unit, returning a plain object. The unit field in the result will be the toUnitIdentifier provided. Prefer convert() followed by toData(), or toData() directly.
    • add(other: IMeasurement<C>): Measurement<C>: Adds another measurement. If units are different but compatible, other is converted to the unit of this measurement.
    • subtract(other: IMeasurement<C>): Measurement<C>: Subtracts another measurement.
    • multiply(scalar: number): Measurement<C>: Multiplies the measurement's value by a scalar.
    • divide(scalar: number): Measurement<C>: Divides the measurement's value by a scalar. Throws an error if scalar is zero.
    • toString(options?: FormatOptions): string: Formats the measurement for display.
    • toJSON(): { value: number; unit: string; category: string }: Returns a JSON-serializable representation, using originalSymbol for the unit field.
  • UnitRegistry: Manages unit definitions and conversion logic. An instance of this class is initialized internally with all predefined units and conversions when the library loads. Users typically do not interact with this class directly.

Units Constants (Units Object)

The library exports a central Units object, which provides a structured and type-safe way to access all available unit symbols. This object is organized by UnitCategory, making it easy to find and use specific units in your code.

Usage

You can access unit symbols like this: Units.CategoryName.UnitConstant. For example, to get the symbol for meters, you would use Units.Length.METER.

import { Measurement, Units } from 'ts-measurements';

// Using the Units object for clarity and type safety
const myLength = new Measurement(10, Units.Length.METER);       // 10 meters
const myWeight = new Measurement(5, Units.Weight.KILOGRAM);     // 5 kilograms
const myTemp = new Measurement(25, Units.Temperature.CELSIUS); // 25 degrees Celsius

console.log(myLength.toString({ includeUnit: true }));    // "10.0000 m"
console.log(myWeight.toString({ includeUnit: true }));    // "5.0000 kg"
console.log(myTemp.toString({ includeUnit: true }));      // "25.0000 °C"

Available Unit Categories and Constants

Below is a comprehensive list of all unit categories and their respective constants available through the Units object:

Units.Length

Constants for length units:

Units.Length = {
  METER: 'm',
  KILOMETER: 'km',
  CENTIMETER: 'cm',
  MILLIMETER: 'mm',
  INCH: 'in',
  FOOT: 'ft',
  YARD: 'yd',
  MILE: 'mi',
};
Units.Weight

Constants for weight units:

Units.Weight = {
  KILOGRAM: 'kg',
  GRAM: 'g',
  MILLIGRAM: 'mg',
  GRAIN: 'gr',
  POUND: 'lb',
  OUNCE: 'oz',
};
Units.Temperature

Constants for temperature units:

Units.Temperature = {
  CELSIUS: '°C',
  FAHRENHEIT: '°F',
  KELVIN: 'K',
};
Units.Angle

Constants for angle units:

Units.Angle = {
  RADIAN: 'rad',
  DEGREE: '°',
  GRADIAN: 'grad',
  MOA: 'moa',        // minute of angle
  MRAD: 'mrad',       // milliradian
  IPHY: 'iphy',       // inches per hundred yards
  CPHM: 'cm/100m',    // centimeters per 100 meters
};
Units.Time

Constants for time units:

Units.Time = {
  SECOND: 's',
  MINUTE: 'min',
  HOUR: 'h',
  MILLISECOND: 'ms',
  MICROSECOND: 'μs',
};
Units.Velocity

Constants for velocity units:

Units.Velocity = {
  METER_PER_SECOND: 'm/s',
  KILOMETER_PER_HOUR: 'km/h',
  MILE_PER_HOUR: 'mph',
  KNOT: 'kn',
  FOOT_PER_SECOND: 'ft/s',
};
Units.Energy

Constants for energy units:

Units.Energy = {
  JOULE: 'J',
  KILOJOULE: 'kJ',
  FOOT_POUND: 'ft⋅lb',
  CALORIE: 'cal',
  KILOCALORIE: 'kcal',
  BTU: 'BTU',
  KILOWATT_HOUR: 'kWh'
};
Units.Pressure

Constants for pressure units:

Units.Pressure = {
  PASCAL: 'Pa',     // pascal
  BAR: 'bar',       // bar
  MBAR: 'mbar',     // millibar
  MMHG: 'mmHg',     // millimeters of mercury
  INHG: 'inHg',     // inches of mercury
  PSI: 'psi',       // pounds per square inch
  ATM: 'atm',       // atmosphere
};
Units.Density

Constants for density units:

Units.Density = {
  KILOGRAM_PER_CUBIC_METER: 'kg/m3', // kilogram per cubic meter
  POUNDS_PER_CUBIC_FOOT: 'lb/ft3',    // pounds per cubic foot

};

Units.Percentage

Constants for percentage units:

Units.Percentage = {
  PERCENT: '%',
};
Units.BallisticCoefficient

Constants for ballistic coefficient units:

Units.BallisticCoefficient = {
  G1: 'G1',
  G2: 'G2',
  G5: 'G5',
  G6: 'G6',
  G7: 'G7',
  G8: 'G8',
  GI: 'GI',
  GS: 'GS',
  GC: 'GC',
};

Type Definitions

  • FormatOptions: An interface defining options for formatting measurement strings with Measurement.toString().

    export interface FormatOptions {
      decimals?: number;        // Number of decimal places
      includeUnit?: boolean;    // Whether to include the unit symbol in the output
      rounding?: 'round' | 'floor' | 'ceil'; // Rounding method
      thousands?: boolean;      // Whether to use thousands separators
      thousandsSeparator?: string; // Character for thousands separator (default: ',')
      decimalSeparator?: string;   // Character for decimal point (default: '.')
      trailingZeros?: boolean;  // Whether to include trailing zeros to match `decimals` (default: false)
    }
    

    The default values are approximately: { decimals: 4, includeUnit: false, rounding: 'round', thousands: false, thousandsSeparator: ',', decimalSeparator: '.', trailingZeros: false }.

  • MeasurementData: An interface representing the basic structure for creating a measurement or getting its plain data.

    export interface MeasurementData {
      value: number;
      unit: string; // Unit symbol, e.g., "kg", "m"
    }
    
  • UnitCategory: An enum representing the available unit categories.

    export enum UnitCategory {
      Length = 'length',
      Weight = 'weight',
      Temperature = 'temperature',
      Angle = 'angle',
      Time = 'time',
      Velocity = 'velocity',
      Energy = 'energy',
      Pressure = 'pressure',
      Density = 'density',
      Percentage = 'percentage',
      BallisticCoefficient = 'ballisticCoefficient',
    }
    

    Used like UnitCategory.Length or UnitCategory.Pressure.

  • Unit: An interface representing a unit definition (name, symbol, category). The category property is of type UnitCategory (the enum).

License

MIT

FAQs

Package last updated on 15 May 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts