-
Notifications
You must be signed in to change notification settings - Fork 13.1k
Improved subtype compatibility rules for types of object literals #1795
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
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.
👍 good change here
To clarify, are we keeping change #1774? I think it would only make a difference for object literals returned from contextually typed function expressions. |
src/compiler/types.ts
Outdated
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.
ContainsObjectLiteral
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.
Also, why do you need both ObjectLiteral and ContainsLiteral?
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 ObjectLiteral flag better enables us to check if a type originated in an object literal (as opposed to contains one). It replaces the old isTypeOfObjectLiteral function that was kind of convoluted.
@JsonFreeman No, #1774 (and it's funny effects on error reporting) is reverted by this. |
👍 |
Conflicts: src/compiler/checker.ts tests/baselines/reference/intTypeCheck.errors.txt
Improved subtype compatibility rules for types of object literals
Fixes #1446.
Fixes #1448.
Fixes #1655.
Fixes #1723.
With this PR the type of an object literal has increased subtype compatibility until it is widened, similar to how we treat null and undefined in expressions.
In #919 we tightened subtyping rules such that optional properties are required to be present in subtypes. This change is desirable because it makes subtyping more selective to the benefit of union types and overload resolution.
However, #919 is too strict in certain situations involving object literals. For example, the object literal
{ a: "foo" }
is not considered a subtype of{ a: string; b?: string; }
because it is missing the optional memberb
. That just doesn't seem right. But at the same time it is entirely meaningful to say that{ a: string }
is a supertype (and not a subtype) of{ a: string; b?: string; }
.The interesting fact here is that when an object literal omits optional properties, we can say for certain those optional properties aren't present, and it is therefore safe to consider it a subtype. But once we infer a variable's type from an object literal, that variable might acquire additional properties that we don't know about and we need to be stricter.
And that's the gist of this PR: The type of an object literal is a subtype of a given type T even when it is missing optional properties from T, but once the object literal type is widened to a regular type that is no longer the case.
An example:
Note the difference between
x1
andy1
. In thex1
case, the object literal argument is considered a subtype ofItem
. It omitteddescription
so we know for suredescription
isn't anything else. But in they1
case,o1
has type{ name: string }
and might very well have adescription
property that isn't of type string. So we can't consider it a subtype.The PR fixes #1446 and provides a better solution to #1723 (effectively removing the fix in #1774). It also fixes #1448 and #1655 which were caused by incorrect tracking of null and undefined types in unwidened types.