-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
awaitedtype -
Held 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.
async function a() { const o: object = Promise.resolve(100); return o; }
-
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?async function foo<T>(x: Promise<T>) { const y: T = await x; // 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.