
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
ts-measurements
Advanced tools
A comprehensive, modern TypeScript library for handling measurements, units, and conversions with type safety and precision.
A comprehensive, modern TypeScript library for handling measurements, units, and conversions with type safety and precision.
npm install ts-measurements
You can create Measurement instances in several primary ways:
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"
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"
fromString Static MethodParse 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"
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"
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".
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)
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"
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.
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.
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"
}
The library supports a wide range of units across various categories:
| Category | Units |
|---|---|
| Length | m, km, cm, mm, in, ft, yd, mi |
| Weight | kg, g, mg, lb, oz, grain |
| Temperature | °C, °F, K |
| Time | s, min, h, d, wk, ms, μs |
| Angle | rad, °, grad, moa, mrad, iphy, cphm |
| Energy | J, kJ, ft⋅lb, cal, kcal, BTU, kWh |
| Velocity | m/s, km/h, mph, kn, ft/s |
| Pressure | Pa, bar, mbar, mmHg, inHg, psi, atm |
| Density | kg/m3, lb/ft3 |
| Percentage | % |
| BallisticCoefficient | G1, 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.
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 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.
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"
Below is a comprehensive list of all unit categories and their respective constants available through the Units object:
Units.LengthConstants for length units:
Units.Length = {
METER: 'm',
KILOMETER: 'km',
CENTIMETER: 'cm',
MILLIMETER: 'mm',
INCH: 'in',
FOOT: 'ft',
YARD: 'yd',
MILE: 'mi',
};
Units.WeightConstants for weight units:
Units.Weight = {
KILOGRAM: 'kg',
GRAM: 'g',
MILLIGRAM: 'mg',
GRAIN: 'gr',
POUND: 'lb',
OUNCE: 'oz',
};
Units.TemperatureConstants for temperature units:
Units.Temperature = {
CELSIUS: '°C',
FAHRENHEIT: '°F',
KELVIN: 'K',
};
Units.AngleConstants 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.TimeConstants for time units:
Units.Time = {
SECOND: 's',
MINUTE: 'min',
HOUR: 'h',
MILLISECOND: 'ms',
MICROSECOND: 'μs',
};
Units.VelocityConstants 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.EnergyConstants for energy units:
Units.Energy = {
JOULE: 'J',
KILOJOULE: 'kJ',
FOOT_POUND: 'ft⋅lb',
CALORIE: 'cal',
KILOCALORIE: 'kcal',
BTU: 'BTU',
KILOWATT_HOUR: 'kWh'
};
Units.PressureConstants 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.DensityConstants 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.PercentageConstants for percentage units:
Units.Percentage = {
PERCENT: '%',
};
Units.BallisticCoefficientConstants for ballistic coefficient units:
Units.BallisticCoefficient = {
G1: 'G1',
G2: 'G2',
G5: 'G5',
G6: 'G6',
G7: 'G7',
G8: 'G8',
GI: 'GI',
GS: 'GS',
GC: 'GC',
};
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).
MIT
FAQs
A comprehensive, modern TypeScript library for handling measurements, units, and conversions with type safety and precision.
The npm package ts-measurements receives a total of 0 weekly downloads. As such, ts-measurements popularity was classified as not popular.
We found that ts-measurements demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

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.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.