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

Probabilistic Types #34714

Open
5 tasks done
greim opened this issue Oct 24, 2019 · 5 comments
Open
5 tasks done

Probabilistic Types #34714

greim opened this issue Oct 24, 2019 · 5 comments
Labels
In Discussion Not yet reached consensus Suggestion An idea for TypeScript

Comments

@greim
Copy link

greim commented Oct 24, 2019

Search Terms

Probabilistic, union, supertypes

Suggestion

If a union type contains a member which is a supertype of one or more other members, the supertype subsumes those other members, but the information isn't lost. Tooling can then use that information as a hint about the expected distribution of possible values within that type.

type MetaSyntacticVar = 'foo' | 'bar' | 'baz' | string;

For the purposes of type safety, the above type is simply string. However, tools may consider 'foo' | 'bar' | 'baz' to be the most likely values for MetaSyntacticVar. An IDE might use them for autocomplete. A linter (i.e. not tsc) might flag other values as a warning. Etc.

Use Cases

A backend service offers a range of options, and I want to statically model them as a union type. Sometimes, the service adds a new option. I must either generalize the type to a string, do a type cast and tolerate some type unsafety, or release code updates in sync with all backend updates.

Examples

type MetaSyntacticVar = 'foo' | 'bar' | 'baz' | string;

const name: MetaSyntacticVar = 'qux';
================================^ IDE suggests foo, bar, or baz as I type this
================================^^^ eslint flags this as a warning (if I opt in)

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, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.
@jcalz
Copy link
Contributor

jcalz commented Oct 25, 2019

I imagine such a change would break existing TypeScript code; if a union of a literal type with its widened supertype doesn't collapse to the supertype, anything that operates on union members (such as distributive conditional types) could behave differently.

With current TS one might achieve something like what you're looking for with a helper function:

const MetaSyntacticVar = <T extends string, U extends "foo" | "bar" | "baz">(t: T | U) => t as T;
const intelliSense = MetaSyntacticVar("qux"); // <-- intellisense prompts "foo", "bar", "baz" too

Capture

Playground link

@greim greim changed the title Probabilistic Union Types Probabilistic Types Oct 25, 2019
@greim
Copy link
Author

greim commented Oct 25, 2019

Thanks for the reply, I changed the title from "Probabilistic Union Types" to just "Probabilistic Types".

'foo' | 'bar' | string simply collapses to string, and from then onward I agree it's just string in terms of what it is and how things operate on it. I'm not proposing to change that.

What I'm proposing instead is that a type T which has a set of N possible values, could carry hints about which of those values are more likely to occur. The type system would ignore those hints, but tooling such as intellisense could use them, and a declaration like 'foo' | 'bar' | string could be a way to add them. Maybe there could be others.

It's a wild idea perhaps, but was prompted by a real problem I was having which I described (in simplified form) in the use cases.

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Oct 25, 2019

Seems related to #26277

@AlCalzone
Copy link
Contributor

AlCalzone commented Oct 25, 2019

I don't remember in which issue this was discussed, but it was proposed this can be solved with branded tag types.

Edit: found it #33471

@sandersn sandersn added In Discussion Not yet reached consensus Suggestion An idea for TypeScript labels Oct 25, 2019
@greim
Copy link
Author

greim commented Oct 26, 2019

@AlCalzone @orta - Yep, that issue addresses the exact problem I was having.

Thinking out loud, if you wanted to exactly specify the expected internal distribution of a type, you could add new syntax. Maybe something like:

type MetaSyntacticVar = 'foo'~4 | 'bar'~3 | 'baz'~2 | string~1;
// expect string 10% of the time, etc

Intellisense could use it for sorting, or linters could warn for values falling below certain thresholds. An IDE could even give feedback about how likely some logic branch would ever be executed, which would be useful during refactoring.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
In Discussion Not yet reached consensus Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

5 participants