Search code examples
typescripttypestype-inferencedivide-by-zero

Typescript type to prevent division by 0


I am creating a calculation system for training purpose with typescript and I get a typing error during division.

Do you have any idea how to solve it?

type Variable = {
    value: number
    resolve: () => number
}

type NoZeroVariable = {
    value: Omit<number, 0>
    resolve: () => Omit<number, 0>
}

// then when I try to resolve the operation
a.resolve() / b.resolve()

I get this error : The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.(2363)


Solution

  • Here you have very simple implementation:

    type NonZero<T extends number> = T extends 0 ? never : number extends T ? never : T
    
    
    const division = <
        A extends number,
        B extends number
    >(a: A, b: NonZero<B>) =>
        a / b
    
    division(10, 2) // ok
    division(10, 0) // error
    
    
    const higherOrderFunction = (b: number) => division(10, b) // error, b is not verified
    
    
    `NonZero` - expects a number. If number is has a literal representation like `1`,`2` or any other literal it returns this number, otherwise (if it is `0` or `number`) it returns `never`
    

    Playground

    b expected to be only literal number. It can't event be some variable with type of number because you don't know the value in runtime.

    Let's proceed wot your example:

    type Variable<N extends number> = {
      value: N
      resolve: () => number
    }
    
    
    type NonZero<T extends number> = T extends 0 ? never : number extends T ? never : T
    
    
    const variableDivision = <
      Num1 extends number,
      Num2 extends number,
    
      >(a: Variable<Num1>, b: Variable<NonZero<Num2>>) =>
      a.resolve() / b.resolve()
    
    variableDivision({ value: 42, resolve: () => 42 }, { value: 42, resolve: () => 0 }) // ok
    variableDivision({ value: 42, resolve: () => 42 }, { value: 0, resolve: () => 0 }) // expected error
    

    It is impossible in TypeScript to overload division operator / like in F#.

    Hence, you need to create an extra function for division.

    Num2 is infered number from b variable. If it is 0, NonZero returns never and the whole b argument becomes Variable<never>. SInce never is unrepresentable, you are getting error. Playground