Type-safe dimensional analysis and units for TypeScript.
Just want SI? @isentropic/dim-si provides ready-to-use SI units with compile-time dimension checking.
dim treats quantities and units as separate concepts with different responsibilities. Units are layered on top of quantities to give them meaning.
A quantity encodes dimensionality. Dimensions are tracked at compile time, so the type checker catches errors like adding a length to a time before your code runs.
A unit gives meaning to a quantity. Units are views over quantities: different lenses for reading and writing the same underlying value.
dim accomplishes this by providing tools for defining quantity and unit systems, and uses those same tools to provide ready-made ISQ quantities and SI units.
Here's what that looks like in practice: a small physics system with length, time, and temperature.
Choose base dimensions and derive compound quantities from them:
import { defineQuantitySystem } from "@isentropic/dim-quantity";
const qs = defineQuantitySystem(["L", "T", "Θ"]);
const length = qs.base("L");
const time = qs.base("T");
const temperature = qs.base("Θ");
const velocity = qs.factory({ L: 1, T: -1, Θ: 0 });At this point, length(100) produces a value tagged with dimension L. No
units, no scale factors, just dimensionality.
For larger systems, dim-quantity supports a spec-based approach with code generation.
Units attach physical meaning to those raw quantities:
import { defineUnitSystem, valueIn } from "@isentropic/dim-unit";
const us = defineUnitSystem("tutorial", qs);
// Base units
const meter = us.unit(length);
const second = us.unit(time);
const kelvin = us.unit(temperature);
// Scaled units
const kilometer = meter.scaled(1000);
const hour = second.scaled(3600);
// Affine units (arbitrary zero point)
const celsius = kelvin.offset(273.15);Now you have type-safe arithmetic with automatic dimension tracking. Wrap any
quantity with q() for fluent chaining:
import { q } from "@isentropic/dim-unit/chain";
const speed = q(kilometer(5)).div(hour(2));
q(kilometer(5)).in(meter); // 5000
q(kilometer(5)).in(kilometer); // 5
// Same-dimension arithmetic works
q(kilometer(1)).plus(meter(500)); // 1500 m
// Dimension mismatches are compile errors
q(kilometer(1)).plus(hour(1)); // Error: length and time dimensions don't match
// Affine units enforce correct semantics
q(celsius(100)).minus(celsius(0)); // 100 K (linear delta)
q(celsius(0)).plus(celsius.delta(10)); // 10°C (affine point)
q(celsius(100)).plus(celsius(0)); // Error: can't add two affine quantitiesFree functions are also available for one-off operations:
import { add, divide } from "@isentropic/dim-unit/ops";
const total = add(kilometer(1), meter(500));
const speed = divide(kilometer(5), hour(2));Defining quantity and unit systems from scratch is useful for custom domains, but most scientific and engineering work uses the same foundational systems: the ISQ (International System of Quantities) for dimensions and derived quantities, and the SI (International System of Units) for units.
Rather than make everyone define these themselves, dim uses its own tooling to provide them as ready-to-use packages.
| Package | Description |
|---|---|
| dim-si | SI unit system built on dim-isq |
| dim-isq | ISQ quantity system |
| dim-unit | Define unit systems with scale factors and affine offsets for any quantity system |
| dim-quantity | Define quantity systems with compile-time dimension tracking |
deno test # Run all tests
deno lint # Lint all files
deno fmt # Format all filesMIT