DEV Community

Acid Coder
Acid Coder

Posted on • Updated on

Typescript Odd Number Type

Most people: No, you cannot create an odd number type with Typescript

Meanwhile me:

type OddNumber<
    X extends number,
    Y extends unknown[] = [1],
    Z extends number = never
> = Y['length'] extends X
    ? Z | Y['length']
    : OddNumber<X, [1, 1, ...Y], Z | Y['length']>

type a = OddNumber<1> // 1 
type b = OddNumber<3> // 1 | 3
type c = OddNumber<5> // 1 | 3 | 5
type d = OddNumber<7> // 1 | 3 | 5 | 7
Enter fullscreen mode Exit fullscreen mode

playground

with some limitations, the input must an odd number, and cannot exceed 1999 (maximum depth of typescript recursion is only 1000)

you can do even number type using similar logic

Discussion (6)

Collapse
ecyrbe profile image
ecyrbe • Edited on

Ok, challenge accepted. If you are not affraid of generic programming you can do Odd or Even type check without limitation :

type Number2String<T extends number> = `${T}`;
type IsStringEven<T extends string> = 
  T extends `${string}${0|2|4|6|8}` ? true : false;

type IsStringOdd<T extends string> = 
  T extends `${string}${1|3|5|7|9}` ? true : false;

type EvenNumber<T extends number> = 
  IsStringEven<Number2String<T>> extends true ? T : never;

type OddNumber<T extends number> = 
  IsStringOdd<Number2String<T>> extends true ? T : never;

function guarantyOddNumber<T extends number>(n: EvenNumber<T>) {
  return n+1;
}

function guarantEvenNumber<T extends number>(n: OddNumber<T>) {
  return n+1;
}

guarantyOddNumber(6876546); // succeed
guarantyEvenNumber(6876546); // fail
Enter fullscreen mode Exit fullscreen mode

check on playground

Collapse
tylim88 profile image
Acid Coder Author • Edited on

good solution, I further simplified your code

type IsEven<T extends number> = 
  `${T}` extends `${number}${0|2|4|6|8}` ? T : never;

type IsOdd<T extends number> = 
  `${T}` extends `${number}${1|3|5|7|9}` ? T : never;

function guarantyOddNumber<T extends number>(n: IsOdd<T>) {
  return n;
}

function guarantEvenNumber<T extends number>(n: IsEven<T>) {
  return n;
}

guarantyOddNumber(6876545); // succeed odd
guarantyOddNumber(6876546); // fail odd
guarantEvenNumber(6876546) // succeed even
guarantEvenNumber(6876545); // fail even
Enter fullscreen mode Exit fullscreen mode

generic

however there is fundamental different between your solution and my original solution

yours can only be used in function, the original solution is intended to assign to a variable, for example

const a:OddNumber = 1
Enter fullscreen mode Exit fullscreen mode

which is why it is a odd number type, not odd number check

I do however agree that the function one is more versatile

Collapse
natescode profile image
Nathan Hedglin

What an abomination. . .but I love it haha

Collapse
lukeshiru profile image
Luke Shiru

My exact thought 🀣

Collapse
chismo950 profile image
chismo950

An odd methodπŸ˜‚

Collapse
tqbit profile image
tq-bit

This type contains more logic than my first customer project.

I draw my 🎩 before that