-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Add the comparability relationship to the spec (attempt two) #20686
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
Conversation
I don't know if I covered this feedback:
|
* *T* is an enum member type, *S* is a literal type, and the literal values of *S* and *T* are identical. | ||
* *S* is a literal type and *T* is the base primitive type of *S*. | ||
* *T* is a literal type and *S* is the base primitive type of *T*. | ||
* *S* is a union type and some constituent type of *S* is comparable to *T*. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this relation 100% symmetric? Can we just say that up front and cut this in half?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or even if it's not, parcel out the symmetric relations, e.g. S is assignable to T if any of the following are true for S* = S, T* = T
or for S* = T, T* = S
... (all symmetric properties here in terms of S* / T*)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@RyanCavanaugh I don't quite understand what you mean. But I'd prefer not to combine these operations so that a reader (or a spec writer 😉) can manually do a diff between the assignability and comparability sections on their own
doc/spec/Types.md
Outdated
* the non-primitive object type is comparable to and from any other object type, and | ||
* when relating any two signatures, each signature is always instantiated using type Any for all type arguments. | ||
|
||
While the comparable relation is often applied bidirectionally on a pair of types, it is not a symmetric relationship. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Answers my above question but deserves a counterexample
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments so far.
* *S* is an enum type and *T* is the primitive type Number. | ||
* *S* is the Never type. | ||
* *S* is the Undefined type and *T* is the Void type. | ||
* *S* is either the Undefined or Null type, and strict null checks ([#strict-null-checks]) are disabled. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we weren't talking about non-strict in the spec.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You already used this in your other PR :(
* *S* is a numeric enum or numeric enum member type and *T* is the primitive type Number. | ||
* *S* and *T* are both enum member types with respective containing enum types *E* and *F* and | ||
* *E* is a subtype of *F*. | ||
* *S* and *T* are both non-const enum types with the same declared name, and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need to bind E and F here too
* *E* is a subtype of *F*. | ||
* *S* and *T* are both non-const enum types with the same declared name, and | ||
* for each enum member *M* in *E*, there exists an enum member declaration *N* in *F* such that *M* and *N* have the same declared name and value. | ||
* *S* is an enum member type, *T* is a literal type, and the literal values of *S* and *T* are identical. | ||
* *S* is a string literal type and *T* is the primitive type String. | ||
* *S* is a union type and each constituent type of *S* is a subtype of *T*. | ||
* *S* is an intersection type and at least one constituent type of *S* is a subtype of *T*. | ||
* *T* is a union type and *S* is a subtype of at least one constituent type of *T*. | ||
* *T* is an intersection type and *S* is a subtype of each constituent type of *T*. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
excess property checks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Already taken care of above in the intro to the section.
doc/spec/Types.md
Outdated
|
||
*TODO: Document the base primitive type.* | ||
|
||
Types are required to be *comparable* in certain circumstances, such as part of when checking whether two values of given types might be equal at runtime using operators like '===', or when using a type assertion. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this list be complete and authoritative? I don't think it's going to be defined elsewhere. And based on your findings, it looks like it already is complete, it just needs to say that these are the only places that comparability happens.
* *S* is either the Undefined or Null type, and strict null checks ([#strict-null-checks]) are disabled. | ||
* *S* is an object type and *T* is the non-primitive `object` type. | ||
* *T* is an object type and *S* is the non-primitive `object` type. | ||
* *S* or *T* is a numeric enum or numeric enum member type and the other is the primitive type Number. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This applies to strings too, doesn't it?
* *S* is an intersection type and at least one constituent type of *S* is comparable to *T*. | ||
* *T* is a union type and *S* is comparable to at least one constituent type of *T*. | ||
* *T* is an intersection type and *S* is comparable to each constituent type of *T*. | ||
* *T* is a type parameter and *S* is a mapped type *{ [P in keyof X]: Y }*, and *Y* is comparable to *X[P]*. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that you have to say that X
is comparable (or identical?) to T
if you don't just use keyof T
in the mapped type itself.
* *S* is a key query type *keyof S'* and *T'* is comparable to *S'*. | ||
* *S* is comparable to *keyof C* where *C* is the constraint of *S*. | ||
* *T* is an indexed access type *T'[K]* and *S* is comparable to *C[K]* where *C* is the constraint of *T'*. | ||
* *T* is a mapped type *{ [P in K]: X }*, *S* is not a mapped type, *keyof S* is identical to *K*, and *S[K]* is comparable to *X*. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the last clause should be S[P] is comparable to X, not S[K].
7ebb064
to
1c5bdd3
Compare
1c5bdd3
to
2fb84d5
Compare
@DanielRosenwasser can we get these in? |
@DanielRosenwasser I would like to have this and its friends be merged or closed |
Fixes #17214.
Subsumes #17215.