ts-arithmetic
TypeScript icon, indicating that this package has built-in type declarations

0.1.1 • Public • Published

Contributors Forks Stargazers Issues MIT License

Type Level Arithmetic

A package of TypeScript utility types to perform all the basic arithmetic operations at the Type Level, without the usual limitations.
Explore the docs »

Report Bug · Request Feature

Table of Contents
  1. About The Project
  2. Getting Started
  3. Usage
  4. Type Utility Reference
  5. Road Map
  6. License

About The Project

Product Name Screen Shot

(back to top)

ts-arithmetic allows you to perform all the basic arithmetic operations at the Type Level, without any of the usual limitations associated with the dreaded "type instantiation is excessively deep and possibly infinite" TypeScript error. All other existing utilities are limited to small positive integers. ts-arithmetic does not have this limitation.

Built With

  • TypeScript

(back to top)

Getting Started

Prerequisites

  • npm install typscript@^4.8.2 --save-dev

Installation

  • npm install ts-arithmetic --save-dev

(back to top)

Usage

Core

import { Add, Subtract, Multiply, Divide, Pow, Compare, Mod } from 'ts-arithmetic'
// Check the docs below for more

// Add any two numbers
type AddExample = Add<1024, 256>
// 1280

// Subtract any two numbers
type SubtractExample = Subtract<400, 1000>
// -600

// Multiply any two numbers
type MultiplyExample = Multiply<25, 50>
// 1250

// Divide any two numbers
type DivideExample = Divide<-1, 800>
// -0.00125

// Raise a number to an integer power
type PowExample = Pow<5, 7>
// 78125

// Compare any two numbers (same rules as JavaScript Array.sort())
type CompareExample = Compare<123456, 20>
// 1

// Get the JavaScript mod (i.e. remainder)
type ModExmaple = Mod<87, 7>
// 3

(back to top)

Type Utility Reference

Arithmetical Operations

Comparison Operations

Other Checks

Sign

Parity

Number Type

Bit Operations


General Operation Semantics

All of the operations behave pretty much how you would expect them to. They all accept positive/negative integers/fractions. There are a few things to note about never, number, unions of numeric literals and literals given in scientific notation (e.g. 8.5e-15)

never

Passing never in for any parameter will always resolve to never.

Unions of numeric literals

Every type operation will distribute over their parameters as though you called the operation once on each member of the provided union type. e.g.

type ThreeOrFour = Add<1, 2|3> // resolves to 3 | 4

type NegFiveOrTen = Negate<5|-10> // reolves to -5 | 10

For operations that take 2 parameters, if a union type is provided for both parameters, then it will be as though you called the operation on each combination of members of the union types. e.g.

type CartesianAdd = Add<3|4, 10|20> // resolves to 13 | 23 | 14 | 24

number

Most of the time, passing number in for any parameter will resolve to number - though not always.

The answer for any specific case can always be worked out if you think of number as meaning the union of all numeric literals i.e.

type number = ... | -1 | -0.999...9 | -0.999...8 | ... | 0 | 0.000...1 | 0.000...2 | ... | 1 | ...

The type utilities will always return the most restrictive union of the results possible.

For example, 0 * X = 0 for all X. So:

type Zero = Multiply<0, number> // resolves to 0

Or for any of the types that already return some subset of number, then that entire subset will be returned. e.g.

type ZeroOrOne = IsPositive<number> // resolves to 0 | 1

But for 1 + X, there is no meaningfull way to simplify down in the same way. So:

type Useless = Add<1, number> // resolves to number

Scientific Notation

Passing in a numeric literal N where -1 < N < 1 in scientific notation e.g. 8.5e-10 will work just fine.

However there is an issue with large numeric literals given in scientific notation e.g. 1e+21. For N where Abs(N) < 1e+21, typescript will automatically resolve this to its expanded form (e.g. 100000000000000000000) so everything will work as normal. But exceeding this limit will cause typescript to resolve the literal in scientific notation.

type Big1 = 1.0000001e+20 // typescript resolves this to 100000010000000000000
type Big2 = 1e+20 // typescript resolves this to 100000000000000000000
type BigSubtract = Subtract<Big1, Big2> // 10000000000000

type TooBig1 = 1.0000001e+21 // typescript resolves this exactly as it appears, 1.0000001e+21
type TooBig2 = 1e+21 // typescript resolves this exactly as it appears, 1e+21
type TooBigSubtract = Subtract<TooBig1, TooBig2> // never

This notation can be supported (and might in the future) but it currently is not.

Add

Add any two numeric literals. It works exactly how you expect it to.

type NormalExample = Add<75, 25> // 100

type NegativeFractionsExample = Add<-1.5, 0.25> // -0.25

type UnionExample = Add<75|5, 25> // 100 | 30

Subtract

Subtract a numeric literal from another.

type NormalExample = Subtract<200, 50> // 150

type NegativeFractionsExample = Subtract<-35.5, 1.75> // -37.25

type UnionExample = Subtract<100|70, 20> // 80 | 50

Multiply

Multiply any two numeric literals.

type NormalExample = Multiply<25, 25> // 625

type NegativeFractionsExample = Multiply<-0.005, 20> // -0.1

type UnionExample = Multiply<2|3, 4> // 8 | 12

type Zero = Multiply<0, 21212> // 0

type AlsoZero = Multiply<0, number> // 0

Divide

Divide a numeric literal by another.

type NormalExample = Divide<25, 5> // 25

type NegativeFractionsExample = Divide<-0.005, 20> // -0.00025

type UnionExample = Divide<100|50, 5> // 20 | 10

type NotPossible = Divide<10, 0> // never

type AbsorbedNever = Divide<10, 2|0> // 5 | never --> 5

// even though number "contains" 0, since Divide distibutes, the never is
// absorbed into the resulting union just like the above example
type Zero = Divide<0, number> // 0

Pow

Raise a numeric literal to an integer exponent. The limitation of integer exponents will be lifted soon.

type NormalExample = Pow<2, 10> // 1024

type UnionExample = Pow<2|3, 10> // 1024 | 59049

type ReciprocalExample = Pow<20.5, -2> // 0.002379535990481

type AlwaysOne = Pow<10, 0> // 1

type AlsoAlwaysOne = Pow<number, 0> // 1

type NotPossible = Pow<0, -1> // never

type AbsorbedNever = Pow<0, -1|5> // never | 0 --> 0

// even though number "contains" negative values, since Pow distibutes, the never is
// absorbed into the resulting union just like the above example
type Zero = Pow<0, number> // 0

type AndAlsoAlwaysOne = Pow<1, number> // 1

type OneOrMinusOne = Pow<-1, 2|3> // 1 | -1

type AlsoOneOrMinusOne = Pow<-1, number> // 1 | -1

type Imaginary = Pow<-1, 0.5> // never

type ZeroOrOne = Pow<0|1, number> // 0 | 1

type AsExpected0 = Pow<0, 0.5> // 0
type AsExpected1 = Pow<1, 0.5> // 1

type NotAvailableYet = Pow<2, 0.5> // never

type AbsorbedNotAvailableYetNever = Pow<2, 0.5|2> // never | 4 --> 4

Mod

Perform a JavaScript remainder (%) operation on any two numeric literals.

type NormalExample = Mod<7, 2> // 1

type UnionExample = Mod<20|19, 10> // 0 | 9

type NegativeExample = Mod<-7, 2> // -1

type FractionExample = Mod<19.99, 7.5> // 4.99

type NotPossible = Mod<5, 0> // never

type ZeroRemainder = Mod<20, 1> // 0

type FractionRemainder = Mod<20.555, 1> // 0.555

type AlwaysZero = Mod<0, 45> // 0

type ReallyItsAlwaysZero = Mod<0, number> // 0

type AbsorbedNever = Mod<10, 3|0> // 1 | never --> 1

Negate

Negate a numeric literal.

type NormalExample = Negate<-12345> // 12345

type UnionExample = Negate<-1 | 2> // 1 | -2

type NumberExample = Negate<number> // number

Abs

Get the absolute value of a numeric literal.

type NormalExample = Abs<-12345> // 12345

type UnionExample = Abs<-1 | 2> // 1 | 2

type NumberExample = Abs<number> // number

Compare

Compare any two numeric literals. Returns -1 | 0 | 1 as per rules in Array.sort().

For Compare<X, Y>

  • -1 --> X is less than Y
  • 0 --> X and Y are equal
  • 1 --> X is greater than Y
type NormalExample1 = Compare<5, 10> // -1
type NormalExample2 = Compare<5, 5> // 0
type NormalExample3 = Compare<10.1234, -5.111> // 1

type UnionExample = Compare<5|10, 7> // -1 | 1

type NumberExample = Compare<number, 7> // -1 | 0 | 1

Gt

Perform a greater than comparison on any two numeric literals.

  • 1 --> X > Y
  • 0 --> X <= Y
type NormalExample1 = Gt<5, 10> // 0
type NormalExample2 = Gt<5, 5> // 0
type NormalExample3 = Gt<10.1234, -5.111> // 1

type UnionExample = Gt<5|10, 7> // 0 | 1

type NumberExample = Gt<number, 7> // 0 | 1

Lt

Perform a less than comparison on any two numeric literals.

  • 1 --> X < Y
  • 0 --> X >= Y
type NormalExample1 = Lt<5, 10> // 1
type NormalExample2 = Lt<5, 5> // 0
type NormalExample3 = Lt<10.1234, -5.111> // 0

type UnionExample = Lt<5|10, 7> // 0 | 1

type NumberExample = Lt<number, 7> // 0 | 1

Eq

Perform a equality comparison on any two numeric literals.

  • 1 --> X === Y
  • 0 --> X !== Y
type NormalExample1 = Eq<5, 10> // 0
type NormalExample2 = Eq<5, 5> // 1

type UnionExample = Eq<5|10, 10> // 0 | 1

type NumberExample = Eq<number, 7> // 0 | 1

GtOrEq

Perform a greater than or equal to comparison on any two numeric literals.

  • 1 --> X >= Y
  • 0 --> X < Y
type NormalExample1 = GtOrEq<5, 10> // 0
type NormalExample2 = GtOrEq<5, 5> // 1
type NormalExample3 = GtOrEq<10.1234, -5.111> // 1

type UnionExample = GtOrEq<5|7|10, 7> // 0 | 1

type NumberExample = GtOrEq<number, 7> // 0 | 1

LtOrEq

Perform a less than or equal to comparison on any two numeric literals.

  • 1 --> X <= Y
  • 0 --> X > Y
type NormalExample1 = LtOrEq<5, 10> // 1
type NormalExample2 = LtOrEq<5, 5> // 1
type NormalExample3 = LtOrEq<10.1234, -5.111> // 0

type UnionExample = LtOrEq<5|7|10, 7> // 0 | 1

type NumberExample = LtOrEq<number, 7> // 0 | 1

Max

Get the greatest of two numeric literals.

type NormalExample1 = Max<5, 10> // 10
type NormalExample2 = Max<50, 5> // 50
type NormalExample3 = Max<10.1234, -5.111> // 10.1234

type UnionExample = Max<5|8|10, 7> // 7 | 8 | 10

type NumberExample = Max<number, 7> // number

Min

Get the smallest of two numeric literals.

type NormalExample1 = Min<5, 10> // 5
type NormalExample2 = Min<50, 5> // 5
type NormalExample3 = Min<10.1234, -5.111> // -5.111

type UnionExample = Min<5|8|10, 7> // 5 | 7

type NumberExample = Min<number, 7> // number

IsPositive

Check if a numeric literal is positive.

type NormalExample = IsPositive<-12345> // 0

type UnionExample = IsPositive<-1 | 2> // 0 | 1

type NumberExample = IsPositive<number> // 0 | 1

IsNegative

Check if a numeric literal is negative.

type NormalExample = IsNegative<-12345> // 1

type UnionExample = IsNegative<-1 | 2> // 0 | 1

type NumberExample = IsNegative<number> // 0 | 1

IsOdd

Check if a numeric literal is odd.

type NormalExample = IsOdd<123> // 1

type FractionExample = IsOdd<3.5> // never

type UnionExample = IsOdd<2 | 3> // 0 | 1

type NumberExample = IsOdd<number> // 0 | 1

IsEven

Check if a numeric literal is even.

type NormalExample = IsEven<123> // 0

type FractionExample = IsEven<3.5> // never

type UnionExample = IsEven<2 | 3> // 0 | 1

type NumberExample = IsEven<number> // 0 | 1

IsInt

Check if a numeric literal is an integer.

type NormalExample = IsInt<123> // 1

type FractionExample = IsInt<3.5> // 0

type UnionExample = IsInt<2 | 3.5> // 0 | 1

type NumberExample = IsInt<number> // 0 | 1

IsNotInt

Check if a numeric literal is not an integer.

type NormalExample = IsNotInt<123> // 0

type FractionExample = IsNotInt<3.5> // 1

type UnionExample = IsNotInt<2 | 3.5> // 0 | 1

type NumberExample = IsNotInt<number> // 0 | 1

And

Perform an AND operation on two Bits.

type OneAndOne = And<1, 1> // 1
type OneAndZero = And<1, 0> // 0
type ZeroAndOne = And<0, 1> // 0
type ZeroAndZero = And<0, 0> // 0

type UnionExample = And<1 | 0, 1> // 0 | 1

Or

Perform an OR operation on two Bits.

type OneOrOne = Or<1, 1> // 1
type OneOrZero = Or<1, 0> // 1
type ZeroOrOne = Or<0, 1> // 1
type ZeroOrZero = Or<0, 0> // 0

type UnionExample = Or<1 | 0, 1> // 1

Xor

Perform an XOR operation on two Bits.

type OneXorOne = Xor<1, 1> // 0
type OneXorZero = Xor<1, 0> // 1
type ZeroXorOne = Xor<0, 1> // 1
type ZeroXorZero = Xor<0, 0> // 0

type UnionExample = Xor<1 | 0, 1> // 0 | 1

Not

Perform an NOT operation on a Bit.

type NotZero = Not<0> // 1
type NotOne = Not<1> // 0

type UnionExample = Not<0 | 1> // 0 | 1

See the open issues for a full list of proposed features (and known issues).

(back to top)

Roadmap

  • Support big numbers e.g. 8.5e+50

License

Distributed under the MIT License. See LICENSE for more information.

(back to top)

Contact

Project Link: https://github.com/arielhs/ts-arithmetic

(back to top)

Package Sidebar

Install

npm i ts-arithmetic

Weekly Downloads

565

Version

0.1.1

License

MIT

Unpacked Size

55.9 kB

Total Files

5

Last publish

Collaborators

  • arielhhs