Skip to content

Math

The math category performs arithmetic in the type system. Every operation accepts number or bigint, supports negative and floating point values, and coerces between number and bigint when a result cannot be represented in the input’s type.

Every math type takes a last type parameter, $O extends $StrictOptions<$O, X.$Options> = {}, whose $fail key defaults to never:

type Add<A extends number | bigint, B extends number | bigint, $O extends $StrictOptions<$O, Add.$Options> = {}>

$O['$fail'] is returned when the operation cannot be computed — most commonly when an input is the wide number or bigint type instead of a literal. Supply your own value to distinguish a failure from a legitimate never result.

type R1 = Add<1, 2> // 3
type R2 = Add<number, 2> // never
type R3 = Add<number, 2, { $fail: 'fail' }> // 'fail'

Internally the operands are converted into a NumericStruct — a sign, digit tuple and exponent, similar to a floating point representation — operated on, then converted back. That machinery lives in numeric-struct.ts and is not part of the public API.

type Add<A extends number | bigint, B extends number | bigint, $O extends $StrictOptions<$O, Add.$Options> = {}>
type Increment<N extends number | bigint> // Add<N, 1>
type R1 = Add<1, 2> // 3
type R2 = Add<1.2, -2> // -0.8
type R3 = Add<1n, 2.3> // 3.3, coerced to number
type R4 = Add<9007199254740992, 1> // 9007199254740993n, coerced to bigint
type R5 = Increment<41> // 42
type Subtract<A extends number | bigint, B extends number | bigint, $O extends $StrictOptions<$O, Subtract.$Options> = {}>
type Decrement<N extends number | bigint> // Subtract<N, 1>
type R1 = Subtract<100, 2> // 98
type R2 = Subtract<1.2, 2> // -0.8
type R3 = Subtract<1n, 2.3> // -1.3, coerced to number
type R4 = Decrement<1> // 0
type Multiply<A extends number | bigint, B extends number | bigint, $O extends $StrictOptions<$O, Multiply.$Options> = {}>
type R1 = Multiply<100, 2> // 200
type R2 = Multiply<1.2, 2> // 2.4
type R3 = Multiply<1n, 2.3> // 2.3, coerced to number
type R4 = Multiply<0.5, 4> // 2
type Divide<A extends number | bigint, B extends number | bigint, $O extends $StrictOptions<$O, Divide.$Options> = {}>

A / B. A result that does not terminate is truncated toward zero to $O['precision'] fractional digits, 16 by default, which gives Divide<1, 3> the same literal as the runtime 1 / 3. When a truncated result has more digits than a number literal holds, more fractional digits are dropped until it fits.

type R1 = Divide<1, 4> // 0.25
type R2 = Divide<1, 0.5> // 2
type R3 = Divide<1, 3> // 0.3333333333333333
type R4 = Divide<2, 3, { precision: 2 }> // 0.66
type R5 = Divide<7n, 2n> // 3n, the same as Quotient

bigint has no fractional values, so when either input is a bigint, Divide is Quotient. A zero divisor returns $O['$fail'], as in Quotient, and so does a precision that is not a non-negative integer literal.

type Quotient<A extends number | bigint, B extends number | bigint, $O extends $StrictOptions<$O, Quotient.$Options> = {}>
type Remainder<A extends number | bigint, B extends number | bigint, $O extends $StrictOptions<$O, Remainder.$Options> = {}>

Integer division. Quotient truncates toward zero, as bigint division and Math.trunc(A / B) do, and Remainder is the type-level A % B, taking the sign of A. Together they satisfy Quotient<A, B> * B + Remainder<A, B> = A. Mixing number and bigint gives a bigint.

type R1 = Quotient<7, 2> // 3
type R2 = Quotient<-7, 2> // -3
type R3 = Remainder<7, 2> // 1
type R4 = Remainder<-7, 2> // -1
type R5 = Quotient<7n, 2n> // 3n

Both cover integers only. A fractional input or a zero divisor returns $O['$fail'], since neither has an integer result to return. Divide gives a fractional result.

type R6 = Quotient<1, 0> // never
type R7 = Quotient<7.5, 2> // never
type R8 = Remainder<1, 0, { $fail: 'fail' }> // 'fail'
type GreaterThan<A extends number | bigint, B extends number | bigint, $O extends $StrictOptions<$O, GreaterThan.$Options> = {}>
type GreaterThanOrEqual<A extends number | bigint, B extends number | bigint, $O extends $StrictOptions<$O, GreaterThanOrEqual.$Options> = {}>
type LessThan<A extends number | bigint, B extends number | bigint, $O extends $StrictOptions<$O, LessThan.$Options> = {}>
type LessThanOrEqual<A extends number | bigint, B extends number | bigint, $O extends $StrictOptions<$O, LessThanOrEqual.$Options> = {}>

GreaterThan performs A > B, GreaterThanOrEqual A >= B, LessThan A < B and LessThanOrEqual A <= B.

type R1 = GreaterThan<100, 2> // true
type R2 = GreaterThan<1.2, 2> // false
type R3 = LessThan<1, 2> // true
type R4 = GreaterThanOrEqual<1, 1> // true
type R5 = LessThanOrEqual<2, 1> // false

All four compare number literals only. They resolve to $O['$fail'] for bigint and for the wide number type. The OrEqual pair returns that $fail value as is, rather than its negation, and is true for two identical number literals even when the comparison alone cannot compute it.

type Max<A extends number | bigint, B extends number | bigint, $O extends $StrictOptions<$O, Max.$Options> = {}>
type Min<A extends number | bigint, B extends number | bigint, $O extends $StrictOptions<$O, Min.$Options> = {}>

Max returns whichever of A or B is larger, and Min whichever is smaller. Both are built on GreaterThan and share its limits.

type R1 = Max<-1, 2> // 2
type R2 = Max<1.2, 2> // 2
type R3 = Min<-1, 2> // -1
type R4 = Min<1.2, 2> // 1.2
type Abs<N extends number | bigint, $O extends $StrictOptions<$O, Abs.$Options> = {}>

The absolute value of N. Returns $O['$fail'] for the wide number and bigint types.

type R1 = Abs<-5> // 5
type R2 = Abs<5> // 5
type R3 = Abs<-1n> // 1n
type R4 = Abs<number> // never
type ToNegative<N extends number | bigint>

ToNegative is exported only through the MathPlus namespace. It converts N to negative, and returns N unchanged if it is already negative or zero.

import type { MathPlus } from 'type-plus'
type R1 = MathPlus.ToNegative<5> // -5
type R2 = MathPlus.ToNegative<0> // 0
type R3 = MathPlus.ToNegative<-5> // -5

There is no MathPlus.ToPositive: that is Abs.

MathPlus also holds every other math type on this page: Abs, Add, Decrement, Divide, GreaterThan, GreaterThanOrEqual, Increment, LessThan, LessThanOrEqual, Max, Min, Multiply, Quotient, Remainder and Subtract. Each is the same type as the top-level one, so MathPlus.Add<1, 2> and Add<1, 2> are the same type.