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

Proposal: Introduce a Relational Comparison Type Relationship #10120

Closed
DanielRosenwasser opened this issue Aug 3, 2016 · 3 comments
Closed
Assignees
Labels
Committed The team has roadmapped this issue Fixed A PR has been merged for this issue Suggestion An idea for TypeScript

Comments

@DanielRosenwasser
Copy link
Member

Problem

Before literal types and union types, it made sense that relational comparison operators and equality comparison operators had the same rules.

Overly-permissive

However, with union types, relational comparisons don't always make sense.

declare let x: string;
declare let y: string | number;

if (x < y) {
    // ...
}

Here, it's not clear that you'll get the "correct" behavior if x and y are not both strings, but TypeScript permits this. Issue #5156 covers this in more detail.

Overly-strict

While the current "comparable" relationship is the most lax relationship, it is also too strict. For instance, consider the following example from #10119:

function f(onethree: 1 | 3, two: 2) {
  return onethree < two;
}

Under the comparable relationship, TypeScript issues an error because the type 2 is not comparable with 1 nor is it comparable with 3.

Proposal

I propose a new relational comparison relationship, in which for any types S and T:

  • If T is a union type, then S is only relationally comparable if S is relationally comparable with each constituent of T.
  • Otherwise, if S is a union type, then S is only relationally comparable to T if each constituent of S is relationally comparable to T.
  • Otherwise, if S is string-like, then S is relationally comparable if T is string-like or Any.
  • Otherwise, if S is number-like, then S is relationally comparable if T is number-like or Any.
  • Otherwise, if S is Any, then S is relationally comparable if T is number-like, string-like, or Any.

To note:

  • Boolean and other unmentioned types are never relationally comparable to anything. The rationale is that you probably didn't want to compare a Boolean with a less-than operator.
  • Any is not relationally comparable to everything - for instance, you can't compare a Boolean with an Any.
  • There should not be a case where a mix of string-like and number-like types are ever relationally comparable.
  • Type parameters are currently not covered here (see below).

Open Questions

It's not clear how this behaves with type parameters. For instance, you might propose that we just check the type parameter's constraint here, but that's not enough. If you constrain T to number | string, then T will not be relationally comparable to itself because two distinct values of type T could each have different types at runtime. See #5156 (comment) for a concrete example.

@DanielRosenwasser DanielRosenwasser added the Suggestion An idea for TypeScript label Aug 3, 2016
@RyanCavanaugh RyanCavanaugh added the In Discussion Not yet reached consensus label Aug 3, 2016
@RyanCavanaugh
Copy link
Member

Otherwise, if S is number-like, then S is relationally comparable if T is number-like or Any.

One caveat is that it's probably not desirable to allow relational operations between differing enum types

@sandersn
Copy link
Member

sandersn commented Nov 10, 2016

After some discussion, we decided in the 9/23 design meeting (#11104) to just raise literal types to their base type in a comparison. This fixes #10119 and friends but not #5156.

@sandersn
Copy link
Member

Fix is up at #12158

@mhegazy mhegazy added the Fixed A PR has been merged for this issue label Nov 15, 2016
@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Committed The team has roadmapped this issue Fixed A PR has been merged for this issue Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

4 participants