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

Add numeric predicate expression literal types #49409

Open
ecyrbe opened this issue Jun 7, 2022 · 3 comments
Open

Add numeric predicate expression literal types #49409

ecyrbe opened this issue Jun 7, 2022 · 3 comments
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@ecyrbe
Copy link

ecyrbe commented Jun 7, 2022

Suggestion

🔍 Search Terms

List of keywords you searched for before creating this issue. Write them down here so that others can find this suggestion more easily and help provide feedback.

number template literal type
template number literal type
expression number literal types
bounded 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

I'd like to see number expression literal types. Like string template literal types but for numbers. But since numbers are computed through expressions, it would be more helpfull to have numbers matching with computation expressions.

📃 Motivating Example

Typescript allows you to define template string literal types like this :

type OddNumberString = `${number}${1|3|5|7|9}`;

But cannot do the same for real numbers.
What if you could indeed declare numbers with expression literal types :

type OddNumber = n`(number+1) % 2 === 0`;
type EvenNumber = n`number % 2 === 0`;

it would match like this :

const odd1: OddNumber = 6; // error
const odd2: OddNumber = 5: // succeed 

The type system would just compute the expression and check that the result should be equal true to match a number.

Only number, bits and logic operators would be allowed inside n`` :

  • +
  • -
  • *
  • /
  • %
  • **
  • >
  • <
  • ==
  • ===
  • <=
  • >=
  • ||
  • &&
  • |
  • &
  • ^

allowing Math functions could also be doable, but not mandatory.

You could also use it with extend ternary operator :

type IsOddNumber<T extends number> = T extends n`(number+1) % 2 === 0` ? true : false;

💻 Use Cases

This could be used to check for non zero positive numbers :

type NaturalNumber = n`number>0`;

Or bounded numbers to express rand results :

type Bounded<MIN extends number,MAX extends number> = n`number>=${MIN} && number <${MAX}`;

type RandomResult = Bounded<0,1>;
@jcalz
Copy link
Contributor

jcalz commented Jun 7, 2022

Related to #26382 and or #15645

I'm not sure how to make sense of the syntax here. It resembles a tagged template literal where n is some function that does a thing I can't really understand, or how you're using the string number in there. Syntax aside, I guess you want some way to express types inhabited by all values x such that typeof x === "number" and f(x) is true, where f(x) is some predicate like (x + 1)%2 === 0 (for OddNumber) or x > 0 (for NaturalNumber although one would not generally say that 0.5 is a natural number). Is that a fair assessment?

I'm not seeing what I'd consider a real-world use case in this suggestion. Ideally there'd be some examples that show why the absence of this feature is a pain point. Like, "It would be nice for the compiler to catch the common mistake where people pass negative or possibly-negative numbers to Math.sqrt()". Of course I don't think that's actually a common mistake, but if it were, it would be a compelling use case for such types. So if it's not protection against the $\sqrt{-1}$ or NaN monster, what is it?

@RyanCavanaugh
Copy link
Member

See also #15480

I am also super curious about use cases

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature labels Jun 8, 2022
@RyanCavanaugh RyanCavanaugh changed the title Add Number expression literal types Add numeric predicate expression literal types Jun 8, 2022
@ecyrbe
Copy link
Author

ecyrbe commented Jun 9, 2022

@jcalz :
Syntax is obviously a suggestion. If you think another one should be clearer. i'm your guest.
And for Natural numbers, thank you for pointing at incomplete definition, here a valid one :

type NaturalNumber = n`(number === number | 0) && number>0`;

As for other use cases :

  • range numbers types can be used to represent domain specific numbers. the most obvious one use case is for dates or time :
const midnight: Bounded<0,23> = 0; // OK
const invalid: Bounded<0,23> = 25; // Error

but also RGB values :

type RGB = {
 r : Bounded<0,255>
 g: Bounded<0,255>
 b: Bounded<0,255>
};
const blue : RGB = { r: 0, g: 0, b: 255 };
const invalid: RGB = { r: 0, g: 0, b: 256 };

Ranges are pretty obvious use cases. This proposal is mainly to support this use case, but allow for more like natural numbers or just non floating numbers.
Other languages like ADA only support Ranges (also modulus types, but javascript don't have the concept).

Here are other use cases :

  • binary number (0 or 1)
  • delta ranges ( for example : [0, 0.2, 0.4, 0.6, 0.8, 1] , see ADA )

In math science, data science, or IA domains, be able to constrain numbers statically as inputs can prevent errors.
I know IA is not the primary focus of javascript, but some are used by the community (tensor flow, ...) and having better typescript support for numerical computation would be a plus.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

3 participants