TS-8-bit
Using TypeScript's Type System to do 8-bit Arithmetic
import {
Byte, Num, Add, Sub, Mul, Div, Mod, Eq, Lt, Gt, Lte, Gte, Lsh, Rsh, And, Xor, Or, Not
} from './ts-8-bit'
// Arithmetic
type A = Num< Add < Byte<12>, Byte<22> > > // + type A = 34
type B = Num< Sub < Byte<47>, Byte<12> > > // - type B = 35
type C = Num< Mul < Byte<31>, Byte<4> > > // * type C = 124
type D = Num< Div < Byte<16>, Byte<8> > > // / type D = 2
type E = Num< Mod < Byte<19>, Byte<4> > > // % type E = 3
// Equality
type F = Eq < Byte<10>, Byte<10> > // == type F = true
type G = Lt < Byte<10>, Byte<10> > // < type G = false
type H = Gt < Byte<20>, Byte<10> > // > type H = true
type I = Lte< Byte<10>, Byte<10> > // <= type I = true
type J = Gte< Byte<20>, Byte<10> > // >= type J = true
// Bitwise
type K = Num< Rsh < Byte<64>, 3 > > // >> type K = 8
type L = Num< Lsh < Byte<23>, 2 > > // << type L = 92
type M = Num< Or < Byte<33>, Byte<7> > > // | type M = 39
type N = Num< And < Byte<12>, Byte<5> > > // & type N = 4
type O = Num< Xor < Byte<22>, Byte<17 > > > // ^ type O = 7
type P = Num< Not < Byte<253> > > // ! type P = 2
Overview
ts-8-bit is an experimental library that does 8-bit arithmetic on TypeScript's type system. It does so by applying bitwise operations on tuples of length 8 (1 byte) and leverages TypeScript conditional type inference to give the result. This project was written as a exercise in TypeScript and is offered as is for anyone who may find it of use.
Requires TypeScript 4.1.2 and above. Example link here.
License MIT
Usage
The following demonstrates basic usage.
import { Byte, Num, Add, Mod } from './ts-8-bit'
// ------------------------------------------------------------------------
//
// Use Byte<T> and Num<T> to map between bytes and numbers
//
// ------------------------------------------------------------------------
type A = Byte<127> // type A = [1, 1, 1, 1, 1, 1, 1, 0]
type B = Num<[1, 1, 1, 1, 1, 1, 1, 0]> // type B = 127
type C = Num< Byte<55> > // type C = 55
// ------------------------------------------------------------------------
//
// ... with math done exclusively on bytes ...
//
// ------------------------------------------------------------------------
type D = Add< // type D = [0, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 1, 0],
[1, 1, 1, 1, 1, 1, 1, 0]
>
// ------------------------------------------------------------------------
//
// ... but can be remapped this way ...
//
// ------------------------------------------------------------------------
type E = Num< Add< Byte<127>, Byte<127> > > // type E = 254
// ------------------------------------------------------------------------
//
// ... and used for stuff like ...
//
// ------------------------------------------------------------------------
type FizzBuzz<T extends Byte<any>> =
Mod<T, Byte<5>> extends Byte<0> ?
Mod<T, Byte<3>> extends Byte<0> ? 'fizzbuzz' : 'buzz' :
Mod<T, Byte<3>> extends Byte<0> ? 'fizz' : ''
type T1 = FizzBuzz< Byte<1> > // type T1 = ""
type T2 = FizzBuzz< Byte<2> > // type T2 = ""
type T3 = FizzBuzz< Byte<3> > // type T3 = "fizz"
type T4 = FizzBuzz< Byte<4> > // type T4 = ""
type T5 = FizzBuzz< Byte<5> > // type T5 = "buzz"
type T6 = FizzBuzz< Byte<6> > // type T5 = "fizz"
//
// ... etc etc
//
type T15 = FizzBuzz< Byte<15> > // type T15 = "fizzbuzz"
// ------------------------------------------------------------------------
//
// ... or something more elaborate ...
//
// ------------------------------------------------------------------------
type IsPrimeOp<
A extends [Bit, Bit, Bit, Bit, Bit, Bit, Bit, Bit],
B extends [Bit, Bit, Bit, Bit, Bit, Bit, Bit, Bit]
> = Num<B> extends 1 ? true :
Num<Mod<A, B>> extends 0 ? false :
IsPrimeOp<A, Sub<B, Byte<1>>>
type IsPrime<
A extends [Bit, Bit, Bit, Bit, Bit, Bit, Bit, Bit]
> = IsPrimeOp<A, Sub<A, Byte<1>>>
type P0 = IsPrime< Byte<3> > // true
type P1 = IsPrime< Byte<4> > // false
type P2 = IsPrime< Byte<5> > // true
type P3 = IsPrime< Byte<6> > // false
type P4 = IsPrime< Byte<7> > // true
type P5 = IsPrime< Byte<8> > // false
type P6 = IsPrime< Byte<9> > // false
type P7 = IsPrime< Byte<10> > // false
type P8 = IsPrime< Byte<11> > // true
type P9 = IsPrime< Byte<12> > // false
type P10 = IsPrime< Byte<13> > // true
type P11 = IsPrime< Byte<14> > // false
type P12 = IsPrime< Byte<15> > // false
type P13 = IsPrime< Byte<16> > // false
type P14 = IsPrime< Byte<17> > // true - pushing recursion limits here
type P15 = IsPrime< Byte<18> > // false