Skip to content

Suggestion: Integer ComparisonΒ #46294

@alita-moore

Description

@alita-moore

Suggestion

πŸ” Search Terms

greater than
less than
equal to
integer
math
adding numbers

βœ… Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

The ability to compare integers as type declarations. Currently you can do so with strings but not numbers, which would be very useful.

πŸ“ƒ Motivating Example

I'm not sure what the best syntax would be but something like

type GreaterThan1 = > 1
type LessThan10 = < 10
type Two = 1 + 1

The motivating example was me trying to define an array with at least 1 element

type ArrayLengthMutationKeys = 'splice' | 'push' | 'pop' | 'shift' | 'unshift';
export type MinLengthArray<Element, Length extends number, ArrayPrototype = [Element, ...Element[]]> = Pick<
	ArrayPrototype,
	Exclude<keyof ArrayPrototype, ArrayLengthMutationKeys>
> & {
	[index: number]: Element;
	[Symbol.iterator]: () => IterableIterator<Element>;
       // suggested feature
	readonly length: > Length
};

πŸ’» Use Cases

A currently functional example of this motivating example is

type AtleastOneLengthArray = [string, ...string[]];

The limitation of which is that if you were to use it like..

const func = (input: AtLeastOneLengthArray) => {}

const array = ["one", "two"]
func(array) // -> Argument of type 'string[]' is not assignable to parameter of type '[string, ...string[]]'

More generally this is useful when defining a value as a number, and if you require that it be less than some number

function assertsAtLeastFive = (input: number): asserts number is > 5 {
  if (input <= 5) throw "error";
}

which has uses when you're doing math manipulation and allows for the requirement of asserting values.

When defining complex typescript functions it's sometimes useful to be able to compare types or even add them. This is particularly useful for recursive methods. To do this comparison currently you need to do something like this..

type FortyFive = '0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|end'

// e.g. "0|1|2" -> ["0", "1|2"]
type Decompose<S> = S extends `${infer FirstNumber}|${infer RestOfSet}` ? [FirstNumber, RestOfSet]  : never;
type ToString<T> = T extends number ? `${T}` : never;

// max for LessThanThis is 45, ToBeCompared can be any integer
type LessThan<ToBeCompared extends number | string, LessThanThis extends number | string, Current=FortyFive> =
  ToString<ToBeCompared> extends Decompose<Current>[0]
    ? ToString<ToBeCompared> extends ToString<LessThanThis>
        ? false
        : true
    : ToString<LessThanThis> extends Decompose<Current>[0]
      ? ToString<LessThanThis> extends Decompose<Current>[0]
        ? false
        : true
      : Decompose<Current> extends never
        ? false
        : LessThan<ToBeCompared, LessThanThis, Decompose<Current>[1]>

// max for GreaterThanThis is 45, ToBeCompared can be any integer
type GreaterThan<ToBeCompared extends number | string, GreaterThanThis extends number | string> = LessThan<GreaterThanThis, ToBeCompared>

// is 1 greater than 2?
type Test1 = GreaterThan<1, 2> // -> false
// is 2 greater than 2?
type Test2 = GreaterThan<2, 2> // -> false
// is 3 greater than 2?
type Test3 = GreaterThan<3, 2> // -> true

// is 2 less than 1?
type Test4 = LessThan<2, 1> // -> false
// is 1 less than 1?
type Test5 = LessThan<1, 1> // -> false
// is 0 less than 1?
type Test6 = LessThan<0, 1> // -> true

But it would be nicer to instead do

// is 1 greater than 2?
type Test1 = 1 > 2 // -> false
// is 2 greater than 2?
type Test2 = 2 > 2 // -> false
// is 3 greater than 2?
type Test3 = 3 > 2 // -> true

// is 2 less than 1?
type Test4 =2 < 1 // -> false
// is 1 less than 1?
type Test5 = 1 < 1 // -> false
// is 0 less than 1?
type Test6 = 0 < 1// -> true

which would be useful, for example

type GetArrayElement<Array, Index, Current = 0> = Current extends Index ? Array[index] : GetArrayElement<Array, Index, Current + 1>

type example = GetArrayElement<["one", "two", "three"], 1>
// example -> "two"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions