-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Design Meeting Notes, 9/8/2017 #18339
Comments
@DanielRosenwasser I don't know if TypeScript has warnings, but probably assigning This kind of thing is also an issue in #4183 |
Let's get back down on Earth for a second. This is a duck! type Circle = { radius: number };
type Square = { side: number };
var c: Circle & Square;
c. | <-- ctrl+space The completion here shows both This operation is represented by AND sign, the operation acts like an AND operation — stop calling it 'intersection' in public, and don't bend it towards being intersection. It's an AND. Read it out loud: variable c is both The idea of collapsing non-overlapping types into On the other hand, keeping the current behaviour and building upon it does have benefits in expressiveness. Consider code like this (real life example): function formatDate(date: Date): JSX.Element | string {
var result = <span> fancy date format with colours and whistles </span>;
result.toString = result.valueOf = () => plain text date format
return result as any;
} This is meant to produce 'a thing' that can be used both as React element, as well as string. It would really help to have a simple mental model for this level of set/category theory expressions. |
@mihailik The reason these things are called intersection/union has its roots in set theory. If you think of types as sets that are inhabited by values, an intersection of two types can accommodate values from the intersection of the sets of values each type can accommodate. You may not personally have encountered a use case for collapsing these types, but it is a sound thing to do from the type system perspective and has practical uses. See for example this question where a user became confused precisely because a The reason it is sound to do is again easy to see if you think of intersections as actual intersections. An intersection of two disjoint sets (two types with mutually exclusive sets of values) is identical to the null set (the never type). For the circle/square example you gave, the proposal doesn't cause any issues. Only if there is an identical property on both with mutually exclusive types (e.g. |
@masaeedu readability is a value in itself, set theory is only a tool. Besides, to satisfy set theory we can just stop calling But great point bringing up the StackOverflow question! However it doesn't look like the problem there is with interface Thing {
name: string;
age: HTMLElement;
}
var oldThing: Thing;
let newThing: Thing = Object.assign({}, oldThing, {
age: XMLHttpRequest <-- no problem???
}); |
We're talking about non-intersecting unit types here; the non-unit-type This is about types like |
@RyanCavanaugh helpful distinction! Within narrow use case of Empty intersection and type A: 0 | 1;
type B: 2 | 3;
// . . . much later in different area of code
var quirk: A & B;
quirk = 1;
~~~
Type '1' is not assignable to type '(0 | 1) & (2 | 3)'. <-- much easier to track and fix than:
Type '1' is not assignable to type 'never'. Note that the current TS compiler produces muddy error message: Don't replace the mess with |
We agree. This logic will simply reduce (but never eliminate to 0 / create a top-level |
@RyanCavanaugh For the type |
For all intersections of non-union types, the behavior is unchanged. This is only about removing "impossible" intersections that appear when applying the intersection distributive rule over union types. In the simplest form, the change is that |
@RyanCavanaugh The notes say:
You seem to be saying this is not what you will do. So in your example, when both |
@masaeedu a few lines below:
|
I was assuming by "unit types" you meant primitive types like |
Nope, it doesn't include unions. A unit type is a literal type (string literals, numeric literals, true, false, undefined, null) or an enum member type. |
The way I understand the edge case algebra here, var oneAndTwo: 1 & 2;
oneAndTwo = 1; // fail, '1' is incompatible with '2' in '1 & 2'
takeOne(oneAndTwo); // OK, '1 & 2' is both '1' and '2' at the same time, satisfies '1'
function takeOne(x: 1) { } |
@mihailik Thanks, that's a good example. So @DanielRosenwasser given that |
It's not a useful road to go down. If you go with the simpler form of "Don't allow those types to be written", you're not really helping anyone who needs help -- no one has shown up here with a mistake caused by accidently writing an uninstantiable intersection type. If you go with the harder form of "Don't allow an instantiation of an uninstantiable type", you quickly find yourself in bad cases. What if someone has something like this? type One = { x: 1 };
type Alpha = { a: string; z?: One };
type Two = { x: 2 };
type Beta = { b: string; z?: Two };
type AB = Alpha & Beta; Well now the property |
You're asking whether In the case here it very straightforwardly reduces via distribution to:
Hence the intuitive sense that " And no, you shouldn't be able to access Anyway, I feel like I'm hijacking the thread here so maybe I'll open an issue about it later or write it in my diary or something. EDIT: Messed up the algebra the first time, fixed. |
Re: rules above, pretty sure it is appropriate for |
@masaeedu collapsing nonsensical type to |
@mihailik If you get a warning wherever absurd types arise |
I think RyanCavanaugh already went through that question above. Here: #18339 (comment) It's not a useful road to go down... |
@mihailik I responded to that comment above. The argument that reducing impossible intersections to Coupled with good error reporting that reflects the steps it walked through in the reduction, this is a useful tool in many scenarios. |
Reduce vacuous intersections
When we talk about unions and intersections we are talking about domains - sets which contain a number of values.
Specifically, when you have an intersection, you have a type that describes values that occupy each constituent of the intersection.
However, for certain sets of types that are completely disjoint, you have a completely empty domain of values.
And the type that describes the set of no values is simply
never
.So for certain types (e.g.
number & string
or"foo" & "bar"
), it makes sense to collapse them down tonever
.There's some strange behavior that might come about from this:
We also get quite large slowdowns - @weswigham's experimental branch of discriminated union nodes takes minutes to compile.
So maybe we don't want to go all the way there. But for unit types, we certainly care.
Current behavior in the compiler:
What about objects with properties that collapse to
never
?Circle & Square
(where each has a discriminated unit-typed property) should becomenever
since thekind
ortype
or whatever discriminating field will becomenever
as well.never
becomes sort of opaque - no clue to the user how they got there.never
.Idea: current implementation just removes these vacuous unit intersection types when constructing unions.
Related issue: Reduce empty intersections to never #18210
Export assignment
#17991
#16769
What do you think this code does?
You're probably wrong.
A: ˙ǝdʎʇ ,ƃuᴉɹʇs, ǝɥʇ s,ʇI
Ideas
What about
export default class
?default
is treated as a modifier here?Revision to tagged template string emit
#18300
emit options:
cache globally to match the current spec
defer the use until
what about variable names, could collide in cases of global scripts
Merge contextual types from overloads
#17819
props
has a specificrefs
type or when another type extends another component.Out of time
The text was updated successfully, but these errors were encountered: