- Notifications
You must be signed in to change notification settings - Fork 13.2k
Description
Update on Collapsing Intersections of Impossible Discriminated Unions
- Turns impossible intersections into
nevers - Submitted a few PRs on DefinitelyTyped and ts-toolbelt
- RWC has one break which is better errors
- Has this PR run on material-ui in the perf test suite?
- Not yet! Let's try it now.
- The last thing that we found was a break in Office UI Fabric for React
- When you're not in
strictNullChecks, we don't addundefinedto the type of optional properties. - So an intersection where a property is optional should not be considered a discriminant.
- Does this only trigger for intersections where all properties are optional?
- Yes.
- Things to keep in mind:
IteratorResultusesundefinedas a discriminant
- When you're not in
- Is a break
- But found a lot of better behavior
- Lots of people doing
&to create filters.- Intersections used to produce absolute garbage for discriminated unions - now we correctly filter them down.
- Wait, why is there a different error baseline for some mapped type thing in the PR?
- New change we've wanted to do for a long time.
- Today, when we resolve the members of a mapped type, we also decide to instantiate each of their respective types.
- But now diving into intersections means that we need to probe a little bit deeper to figure out if it needs to reduce, but that can trigger some circularities in exploring types.
- A test in Redux ORM test had a bunch of issues in inference because of recursive types - doing the intersection reduction cause circularity issues, this deferral on mapped type property types fixes this.
- Helps material-ui by 10%, though the intersection work offsets this a bit.
Update on awaited
Looking to reintroduce the
awaitedtypeHeld off on this because people wanted to do recursive digging on any type
- Thought conditionals would fix this.
- It doesn't!
We had a ton of PR s to fix up
Promise.all,Promise.race, etc.- All of them broken in different wonderful ways.
Have one assignability rule that's not sound but is useful:
awaited Srelates toawaited TifSrelates toT- Not sound because subtypes might introduce a
then()method. - But practically doing otherwise would be too restrictive.
- What about
awaited object- Should that be
unknown?- Yeah, feels right.
- What about
awaited{}?{}- But it could be
nullorundefined!
- Should that be
- Need to think about this.
awaited{} ->{}feels okayish,awaited object -> objectfeels wrong
- Not sound because subtypes might introduce a
What about a carve-out from objects in expression positions? Things that come from object literals are
awaitedto themselves, anything else becomes something else.awaitonPromise<object>already gives youobject- Also,
Promise<object>such that the dynamic/runtype type of theobjectis aPromisecan never exist on an A+ Promise - so this is rare in practice.
- Also,
Some other stuff seems broken.
asyncfunctiona(){consto: object=Promise.resolve(100);returno;}
objectis so useless - but what is the distinguishing factor betweenobjectandPointandBox?- The latter two are practically thought of as Promises.
Wasn't
objectwas always broken? Maybe it doesn't matter what happens here.- [[Flurry of argument around which is broken:
objector{}]]
- [[Flurry of argument around which is broken:
We just need to acknowledge where the type holes are.
What about the breaks from
awaited Tnot being assignable toT?asyncfunctionfoo<T>(x: Promise<T>){consty: T=awaitx;// used to work, errors now.}
Again, is this a necessary break? You can almost never construct a
Promise<...>in place ofT, so you could never end up withPromise<Promise<T>>.- But you can write this in the type system.
So what are we feeling?
awaited Promise<object>->object: yesawaited object->object: No?- Feels like maybe it should be
unknown? - Why would you write
objectand intend for it to bePromise? That's practically never the intent.- So maybe it doesn't matter that much?
- Feels like maybe it should be
Joke: what about
T extends nonpromise?- "The opposite of a Promise is a campaign pledge."
What about conditionals?
- Is
awaited (T extends Foo ? T : Promise<T>)assignable to(T extends Foo ? T : Promise<T>).
- Is
Conclusion
- Iterate
- @rbuckton to file a bug on
downlevel-dts
Optional Chaining and Non-Null Assertions
!in the middle of a chain is a chain,!at the end is not.- Seems funny, but appropriate.
Update on CommonJS Emit for Exports
- Had issues with using getters for
export *when a module overrides exports from anexport *.- We were writing getters for properties before they got overwritten.
- Now we set every export ahead of time to
undefinedso that our__exportStarhelper doesn't try to trample over the properties with getters.