Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggestion: Integer Comparison #46294

Closed
5 tasks done
alita-moore opened this issue Oct 10, 2021 · 1 comment
Closed
5 tasks done

Suggestion: Integer Comparison #46294

alita-moore opened this issue Oct 10, 2021 · 1 comment

Comments

@alita-moore
Copy link

alita-moore commented Oct 10, 2021

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"
@jcalz
Copy link
Contributor

jcalz commented Oct 10, 2021

Duplicate of #26382 more or less (pun intended)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants