@buge/ts-units

中文文档
1.2.3发布于 2023/12/20Apache-2.0TypeScriptCommonJS零依赖近 30 天下载 7090

Physical Units for TypeScript

原始使用文档
文档目录41 节
  1. Basic Usage
  2. Displaying
  3. Conversion
  4. Comparing
  5. Addition and Subtracting
  6. Multiplication and Division
  7. Built-in Units
  8. Planar Angles
  9. Solid Angles
  10. Area
  11. Electrical Capacitance
  12. Electric Charge
  13. Electrical Conductance
  14. Electrical Current
  15. Electrical Inductance
  16. Electrical Resistance
  17. Electric Voltage
  18. Energy
  19. Force
  20. Frequency
  21. Length
  22. Luminous Flux
  23. Illuminance
  24. Luminous Intensity
  25. Magnetic Flux
  26. Mass
  27. Scalar
  28. Speed
  29. Power
  30. Pressure
  31. Radioactivity
  32. Absorbed and Equivaelnt Doses of Ionizing Radiation
  33. Temperature
  34. Time
  35. Volume
  36. Defining new Units
  37. Defining new Dimensions
  38. Defining new Arithmetic
  39. Limitations
  40. Lack of Kinds
  41. Lack of input flexibility

Physical Units for TypeScript

CI Build npm version

@buge/ts-units is a package for modeling typed physical units in TypeScript.

It allows you to tell users what you need in a typesafe manner

function setTemperature(t: Temperature) {
  ...
}

while letting them work in units that make sense to them

setTemperature(celsius(21.3));

Units can easily be converted from one to another

const t = celsius(21.3).in(fahrenheit);

compared

meters(1) < feet(4);

and used in mathematical expressions

const length = meters(5).plus(centimeters(3));
const speed = length.per(seconds(2));

Basic Usage

Install from npm or using your favorite package manager:

npm install @buge/ts-units

Simply declare quantities using the built-in units:

import {Length, meters} from '@buge/ts-units/length';
const length: Length = meters(5);

See Built-in Units below for an overview of all built-in units.

Displaying

Quantities provide a toString() method that allows them to be easily rendered to a string:

celsius(23.1).toString(); // '23.1ºC'

For custom formatting, the amount and symbol can be easily extracted from the quantity:

const temp = celsius(23.1);
const html =
  `<span class="amount">${temp.amount.toFixed(1)}</span>` +
  `<span class="symbol">${temp.unit.symbol}</span>`;

Conversion

Quantities can easily be converted from one unit to another using the in method:

const length = meters(5.3).in(feet);
const temp = celsius(23.1).in(fahrenheit);

Quantities can (perhaps obviously) only be converted from units belonging to the same physical dimension in this way, but see Multiplication and Division below for some more advanced conversions.

Comparing

Quantities can be freely compared to one another using standard TypeScript operators (thanks to valueOf):

meters(1) < feet(4);

Because of the inprecision in floating point arithmetics, you should prefer to use the isCloseTo method when checking a quantity for equality:

// Returns whether 1m is within 0.01 feet of 3.28 feet.
meters(1).isCloseTo(feet(3.28), 0.01);

Addition and Subtracting

Quantities of the same physical dimension can be freely added using plus and subtracted using minus:

const time = minutes(3).plus(seconds(2));
const length = meters(5).minus(feet(1));

The unit of the quantities returned will default to the unit of the quantity being added or subtracted.

Multiplication and Division

Quantities can be multiplied with times and divided with per, resulting in new dimensions being returned:

const area: Area = meters(5).times(meters(6));
const speed: Speed = kilometers(150).per(hours(2));

A special case are multiplications with dimensionless units which result in the same unit being returned:

const length: Length = meters(5).times(percent(10)); // 0.5m

You can square and cube quantities and take their reciprocal:

const area: Area = meters(3).squared();
const volume: Volume = meters(2).cubed();
const frequency: Frequency = seconds(3).reciprocal();

You can use the relationship between quantities to define unit conversions:

const riceDensity = grams(220).per(cups);
const iNeed = grams(500).per(riceDensity).in(ounces);

Built-in Units

Here’s a reference of all units that we currently have built in to the library.

Planar Angles

import {Angle, degrees, sin} from '@buge/ts-units/angle';
const angle: Angle = degrees(30);
const s = sin(angle);

Units:
radians, degrees, turns

Trigonometric Functions:
sin, cos, tan, asin, acos, atan, atan2

Solid Angles

import {SolidAngle, steradians} from '@buge/ts-units/angle/solid';
const angle: SolidAngle = steradians(1);

Units:
steradians, squareDegrees

Area

import {Area, squareMeters} from '@buge/ts-units/area';
const area: Area = squareMeters(15);

Units:
squareMeters

Electrical Capacitance

import {Capacitance, microfarads} from '@buge/ts-units/eletric/capacitance';
const capacitance: Capacitance = microfarads(4700);

Units:
farads, microfarads, nanofarads, picofarads

Electric Charge

import {Charge, coulombs} from '@buge/ts-units/eletric/charge';
const charge: Charge = coulombs(5000);

Units:
coulombs

Electrical Conductance

import {Conductance, siemens} from '@buge/ts-units/eletric/conductance';
const conductance: Conductance = siemens(0.2);

Units:
siemens

Electrical Current

import {Current, amperes} from '@buge/ts-units/eletric/current';
const current: Current = amperes(10);

Units:
amperes

Electrical Inductance

import {Inductance, henries} from '@buge/ts-units/eletric/inductance';
const inductance: Inductance = henries(1);

Units:
henries

Electrical Resistance

import {Resistance, ohms} from '@buge/ts-units/eletric/resistance';
const resistance: Resistance = ohms(560);

Units:
ohms

Electric Voltage

import {Voltage, volts} from '@buge/ts-units/eletric/voltage';
const voltage: Voltage = volts(220);

Units:
volts

Energy

import {Energy, joules} from '@buge/ts-units/energy';
const energy: Energy = joules(4.1868);

Units:
joules

Force

import {Force, newtons} from '@buge/ts-units/force';
const force: Force = newtons(608);

Units:
newtons

Frequency

import {Frequency, hertz} from '@buge/ts-units/force';
const frequency: Frequency = hertz(608);

Units:
hertz

Length

import {Length, meters} from '@buge/ts-units/length';
const length: Length = meters(5);

Metric Units:
meters, kilometers, centimeters, millimeters, micrometers, nanometers, picometers, femtometers, fermi, angstroms, microns

Imperial Units:
yards, feet, inches, chains, furlongs, miles

Marine Units:
fathoms, nauticalMiles

Astronomical Units:
astronomicalUnits

Luminous Flux

import {Flux, lumes} from '@buge/ts-units/luminous/flux';
const flux: Flux = lumens(800);

Units:
lumens

Illuminance

import {Illuminance, lux} from '@buge/ts-units/luminous/illuminance';
const illuminance: Illuminance = lux(35000);

Units:
lux

Luminous Intensity

import {Intensity, candelas} from '@buge/ts-units/luminous/intensity';
const intensity: Intensity = candelas(135);

Units:
candelas

Magnetic Flux

import {Flux, webers} from '@buge/ts-units/magnetic/flux';
const flux: Flux = webers(800);

Units:
webers

Mass

import {Mass, kilograms} from '@buge/ts-units/mass';
const mass: Mass = kilograms(5);

Units:
kilograms, grams

Scalar

Technically not a physical dimension but still very useful.

import {Scalar, percent} from '@buge/ts-units/scalar';
const scalar: Scalar = percent(20);

Units:
percent, permille, permyriad

Speed

import {Speed, metersPerSecond} from '@buge/ts-units/speed';
const speed: Speed = metersPerSecond(343);

Units:
metersPerSecond, kilometersPerHour, milesPerHour, knots, feetPerSecond

Power

import {Power, watts} from '@buge/ts-units/power';
const power: Power = watts(800);

Units:
watt

Pressure

import {Pressure, pascals} from '@buge/ts-units/pressure';
const pressure: Pressure = pascals(101325);

Units:
pascals

Radioactivity

import {Radioactivity, becquerels} from '@buge/ts-units/radioactive/decay';
const radioactivity: Radioactivity = becquerels(20);

Units:
becquerels

Absorbed and Equivaelnt Doses of Ionizing Radiation

import {Dose, grays, sieverts} from '@buge/ts-units/radioactive/dose';
const absorbed: Dose = grays(20e-6);
const equivaelnt: Dose = sieverts(1.5e-3);

Units:
grays, sieverts

Temperature

import {Temperature, celsius} from '@buge/ts-units/temperature';
const temperature: Temperature = celsius(23.1);

Units:
kelvin, celsius, fahrenheit, rankine

Time

import {Time, minutes} from '@buge/ts-units/time';
const time: Time = minutes(5);

Units:
seconds, milliseconds (msec), microseconds (usec), nanoseconds, minutes, hours

Volume

import {Volume, cubicMeters} from '@buge/ts-units/volume';
const volume: Volume = cubicMeters(3);

Units:
cubicMeters

Defining new Units

New units of existing dimensions can easily be defined on the basis of an existing one. As an example, here’s how the yard is defined:

const yards: Unit<Length> = meters.times(0.9144).withSymbol('yd');

Similar how quantities can be multiplied and divided you can create new derived units by multiplying them using time, dividing them using per, squaring them using squared, cubing using cubed and taking their reciprocal using reciprocal.

const knots: Unit<Speed> = nauticalMiles.per(hours).withSymbol('kn');
const mps2: Unit<Acceleration> = meters
  .per(seconds.squared())
  .withSymbol('m/s²');

As shown above, you can configure the symbol for the unit using withSymbol that will be suffixed to the amount when printing a quantity using toString(). You can provide any arbitrary string. The symbol can be retrieved from the unit using the .symbol property or from a quantity using .unit.symbol.

We provide a dedicated method to create derived units with SI prefix that both scale the unit and prepend the prefix to the symbol.

const micrograms = gram.withSiPrefix('μ');
micrograms(2.13).toString(); // 2.13μg

The supported SI prefixes are enumerated in unit.SiPrefix.

Defining new Dimensions

We provide units and dimensions for all SI base units and for many derived units. These can be used as building blocks for defining many other units.

Sometimes, you’ll find yourself wanting to define units for a new substance or “thing” though.

Measurable things are defined through “dimensions”. In scientific literature a dimension is often denoted with capital letters and square brackets. For example, the dimension of length is often denoted as [L], that of area as [L]2 and that of speed as [L][T]-1.

We ensure type safety by encoding the dimensions of units and quantities as TypeScript Literal Types. For example, the dimension mentioned above are defined as:

type Length = {length: 1};
type Area = {length: 2};
type Speed = {length: 1; time: -1};

To define a new dimension, start by defining a literal type for it. You’ll also need to define a constant for it that can be used at runtime, since TypeScript types all disappear after compilation. For example, if you would like to introduce quantities of money you might write:

// In money/dimension.ts
export type Money = {money: 1};
export const Money: Money = {money: 1};

We use a convention that we use the same capitalization for the type and for the constant value since it allows us (in most cases) to just forget about whether we are using the type or the value. We also store the dimension in a dimension.ts alongside the units so that we can distinguish Length as a dimension vs. a Length as an amount of a quantity.

Next, you will want to define a base unit for the dimension. Let’s take the US dollar as the base unit:

// In money/units.ts
import * as dimension from './dimension';
export type Money = Quantity<number, dimension.Money>;
export const dollars: Unit<number, dimension.Money> = makeUnit('$', dimension.Money);

You can now use your new dimension and unit to define quantities:

const pleaseDonateToACharityOfYourChoice: Money = usd(10);

Defining new Arithmetic

The default units provided by the library are all based on the native representation of JavaScript number which could lead to a precision error. The most infamous example being (0.1 + 0.2).

The library provides a way to avoid this problem by giving you the possibility to implement your own arithmetic. Each group of units exposes a function withValueType that returns the units using your own arithmetic.

Concretely, you can use other external library that provides more robust representation of numbers. For instance decimal.js:

import {Arithmetic, Geometric} from "@buge/ts-units";
import {Decimal } from 'decimal.js';
import {withValueType as temperatureWithValueType} from '@buge/ts-units/temperature';
import {withValueType as angleWithValueType} from '@buge/ts-units/angle';

const DecimalArithmetic: Arithmetic<Decimal> = {
  fromNative(value: number): Decimal {
    return new Decimal(value);
  },
  toNative(value: Decimal): number {
    return value.toNumber();
  }
  add(left: Decimal, right: Decimal): Decimal {
    return left.add(right);
  },
  sub(left: Decimal, right: Decimal): Decimal {
    return left.sub(right);
  },
  mul(left: Decimal, right: Decimal): Decimal {
    return left.mul(right);
  },
  div(left: Decimal, right: Decimal): Decimal {
    return left.div(right);
  },
  pow(base: Decimal, exponent: Decimal): Decimal {
    return base.pow(exponent);
  },
  abs(value: Decimal): Decimal {
    return value.abs();
  },
  compare(left: Decimal, right: Decimal): number {
    return left.comparedTo(right);
  }
};

const {celsius} = temperatureWithValueType(DecimalArithmetic);

// Planar Angles needs also an implementation of geometric.
const DecimalGeometric: Geometric<Decimal> = {
    sin(value: Decimal): Decimal {
        return value.sin();
    },
    cos(value: Decimal): Decimal {
        return value.cos();
    },
    tan(value: Decimal): Decimal {
        return value.tan();
    },
    asin(value: Decimal): Decimal {
        return value.asin();
    },
    acos(value: Decimal): Decimal {
        return value.acos();
    },
    atan(value: Decimal): Decimal {
        return value.atan();
    },
    atan2(left: Decimal, right: Decimal): Decimal {
        return Decimal.atan2(left, right);
    }
};

const {radians, sin, cos} = angleWithValueType(DecimalArithmetic, DecimalGeometric);

Finally, if you want to create your units from scratch using your own arithmetic, you can use the function makeUnitFactory.

import * as dimension from './dimension';
import {DecimalArithmetic} from './arithmetic'

const {makeUnit} = makeUnitFactory(DecimalArithmetic);

export type Money = Quantity<Decimal, dimension.Money>;
export const dollars: Unit<Decimal, dimension.Money> = makeUnit('$', dimension.Money);

Limitations

Lack of Kinds

Two types are compatible if they share the same dimensions. That is, they can be reduced to the same base unit equivalents. This can mean that some things may be compatible when the actually should not be:

setFrequency(hertz(100));
setFrequency(becquerels(100));

radiationAlarm(grays(2));
radiationAlarm(sieverts(2));

ISO 80000-1:2009(E) defines these as separate “kinds” but we currently provide no way to check for the kind of a quantity at compile time or runtime.

In some cases we have taken the liberty to model the kind of a quantity as a different unit, specifically with planar angles and solid angles. While these are strictly a dimensionless quantity of [L]/[L] and [L]^2/[L]^2 respectively, we model these as:

type Angle = {angle: 1};
type SolidAngle = {angle: 2};

Lack of input flexibility

Currently when declaring quantities you can only use native number as input.

import {meters} from '@buge/ts-units/length';
// It won't work
const length = meters('5');
import {withValueType} from '@buge/ts-units/length';
const { meters } = withValueType(DecimalArithmetic);
// It won't work
const length = meters(new Decimal(5));

Moreover, the arithmetic function of Unit and Quantity also support only native number.

It could be improve in future

版本与发布记录

@buge/ts-units 共发布 6 个版本,首次发布于 2021/08/25;过去 12 个月发布了 0 个版本。

版本发布日期距今
1.2.3latest2023/12/202 年前
1.2.22022/12/033 年前
1.2.12022/11/024 年前
1.2.02021/10/045 年前
1.1.02021/08/255 年前
1.0.02021/08/245 年前

关于 @buge/ts-units 的常见问题

@buge/ts-units 是什么?

Physical Units for TypeScript

如何安装 @buge/ts-units?

在项目目录运行 npm install @buge/ts-units,或使用 pnpm add / yarn add / bun add。

@buge/ts-units 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@buge/ts-units 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@buge/ts-units 可以商用吗?

@buge/ts-units 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@buge/ts-units 的下载量有多少?

根据 npm 官方下载统计,@buge/ts-units 在 2026/10/09 – 2026/11/07 这 30 天内被下载 7,090 次,日均约 236 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@buge/ts-units 还在维护吗?

最新版本 1.2.3 发布于 2023/12/20(2 年前);至今共发布 6 个版本,其中过去 12 个月发布了 0 个;首次发布于 2021/08/25。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。