Closed
Description
Improved inference for object literals
- When dealing with object literals, we know exactly what properties are present.
- So the idea is: whenever fresh object literal types occur together in a union, we can factor them into a more well-understood type.
- This new process is called object literal type normalization, and is performed during widening.
- This means that if widening does not need to occur, normalization doesn't occur.
- For example, if an explicit type is given, we don't need to widen, so we verify against the most exact version we start with.
// 'objs' has an element type of
// { a: number, b: number } |
// { a: string, b?: undefined } |
// { a?: undefined, b?: undefined }
let objs = [ {a: 1, b: 2}, { a: "abc"}, {} ];
let obj = obj[randomInt()];
obj.a; // string | number | undefined
obj.b; // number | undefined
- We need to look into
this
-types, since we don't use normalized properties in that context. - What about when you're in non-
strictNullChecks
mode?- If you have one object with
color
and another withcolour
, now both are available, whereas before you'd get{}
which would eventually raise your own suspicions when you couldn't use the types. - Yes, it is a step backwards in this regard.
- If you have one object with
- Why don't we just always include
| undefined
on properties that occur in a union of object types?-
e.g.
declare let a: {x: ''}; declare let b: {}; let objs = [a, b]; objs[0].x // should this be 'string | undefined'?
-
No, you don't have a license to do this because the object types may have other properties that aren't listed; this only works with exact types.
-
- This is techncally a breaking change because previously we would eventually infer
{}
.- That means anything was subsequently assignable.
- Does that come up often? Is that even desirable?
- Real world code didn't break at all.
- What about in type argument inference?
- Yes, we do the same thing now as well.
- So given all of this work, do we want to continue even doing best-common-supertype inference? Why not just return a union?
- Most cases where we looked into this seemed undesirable.
- These are associated with the breaking changes from when we introduced union types at Breaking changes associated with Union Types #868.
- Conclusions
- Continue discussing union inference
- Continue discussing non-inferential or lower-priority inference
- Continue discussing whether we can introduce a way to specify whether inference produces a union vs a single BCT.
- But overall 👍 on the PR as it is.
Better error spans in array literals
- Currently Improved type inference for object literals #19513 doesn't actually address everything in Omnibus fresh object subtype reduction / contextual type issue #19236.
- Why not return an error whenever an array element isn't compatible with a contextual type?
- You'd potentially report two errors: one on the array (or on an identifier), one on the element.
- Conclusion: Ryan will experiment.
Tuple freshness & stricter tuple behavior
- Maybe we should issue an excess array literal element error?
- Okay, but why not error on length mismatches for all tuple types?
- Have them have an explicit
length
property? - Maybe also have them derive from
ReadonlyArray
?
- Have them have an explicit
strictTupleTypes
?- To be continued.