ts

type N_ZERO = []
type NUM = N_ZERO | [NUM]
type INC<N> = [N]
type DEC<N> = (
  N extends [infer M]
  ? M
  : never
)
{
  let x: DEC<INC<N_ZERO>> = [];
}
type ADD<N, M> = (
  M extends N_ZERO
  ? N
  :
  // ADD<INC<N>, DEC<N>>
  // Type alias 'ADD' circularly references itself.
  {
    0: ADD<INC<N>, DEC<M>>,
    1: never
  }[N extends any ? 0 : 1]
)
{
  let x: ADD<[[]], [[]]> = [[[]]];  // 1 + 1 == 2
}
type N_ONE = INC<N_ZERO>;
type MUL<N, M, S = N_ZERO> = (
  M extends N_ZERO
  ? S
  :
  {
    0: MUL<N, DEC<M>, ADD<S, N>>,
    1: never
  }[N extends any ? 0 : 1]
)
 
type N_TWO = INC<N_ONE>
type N_THREE = INC<N_TWO>
{
  let x: MUL<N_ONE, N_ONE> = [[]];  // 1 * 1 == 1
} {
  let x: MUL<N_TWO, N_ONE> = [[[]]];  // 2 * 1 == 2
} {
  let x: MUL<N_ONE, N_TWO> = [[[]]];  // 1 * 2 == 1
} {
  let x: MUL<N_TWO, N_TWO> = [[[[[]]]]];  // 2 * 2 == 4
}

ts

type N_0 = N_ZERO;
type N_1 = N_ONE;
type N_2 = N_TWO;
type N_3 = [N_2];
type N_4 = [N_3];
type N_5 = [N_4];
type N_6 = [N_5];
type N_7 = [N_6];
type N_8 = [N_7];
type N_9 = [N_8];
type N_TEN = [N_9];
 
type DIGITS2<N, M> = MUL<N, N_TEN, M>
 
// try "N - M", return answer or null
type MINUS<N, M> = (
  M extends N_0
  ? N
  : (
    {
      0: null,
      1: MINUS<DEC<N>, DEC<M>>
    }[N extends N_0 ? 0 : 1]
  )
)
 
{
  let x: MINUS<N_5, N_2> = {} as N_3
} {
  let x: MINUS<N_2, N_5> = null;
}
 
type DIVIDE<
  N, M,
  Q = N_0,
  N1 = MINUS<N, M>
  > = (
    {
      0: [Q, N],
      1: DIVIDE<N1, M, INC<Q>>
    }[N1 extends null ? 0 : 1]
  )
{
  let x: DIVIDE<MUL<N_3, N_4>, N_TEN> = {} as [N_1, N_2]
}
{
  let x: DIVIDE<MUL<N_7, N_8>, N_TEN> = {} as [N_5, N_6]
  // Type instantiation is excessively deep and possibly infinite.
}

I can do 5 * 6 30, but not 6 * 7 42.


This page is auto-translated from /nishio/TypeScriptの型で自然数を作る using DeepL. If you looks something interesting but the auto-translated English is not good enough to understand it, feel free to let me know at @nishio_en. I’m very happy to spread my thought to non-Japanese readers.