Skip to content

Commit e483ea5

Browse files
committed
Use a single union type for all inferred object literal types
1 parent 1641f9b commit e483ea5

1 file changed

Lines changed: 26 additions & 10 deletions

File tree

src/compiler/checker.ts

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9027,7 +9027,7 @@ namespace ts {
90279027

90289028
if (isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True;
90299029

9030-
if (getObjectFlags(source) & ObjectFlags.ObjectLiteral && source.flags & TypeFlags.FreshLiteral) {
9030+
if (isObjectLiteralType(source) && source.flags & TypeFlags.FreshLiteral) {
90319031
if (hasExcessProperties(<FreshObjectLiteralType>source, target, reportErrors)) {
90329032
if (reportErrors) {
90339033
reportRelationError(headMessage, source, target);
@@ -9597,15 +9597,15 @@ namespace ts {
95979597
if (relation === identityRelation) {
95989598
return propertiesIdenticalTo(source, target);
95999599
}
9600-
const requireOptionalProperties = relation === subtypeRelation && !(getObjectFlags(source) & ObjectFlags.ObjectLiteral);
9600+
const requireOptionalProperties = relation === subtypeRelation && !isObjectLiteralType(source);
96019601
const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties);
96029602
if (unmatchedProperty) {
96039603
if (reportErrors) {
96049604
reportError(Diagnostics.Property_0_is_missing_in_type_1, symbolToString(unmatchedProperty), typeToString(source));
96059605
}
96069606
return Ternary.False;
96079607
}
9608-
if (getObjectFlags(target) & ObjectFlags.ObjectLiteral) {
9608+
if (isObjectLiteralType(target)) {
96099609
for (const sourceProp of getPropertiesOfType(source)) {
96109610
if (!getPropertyOfObjectType(target, sourceProp.escapedName)) {
96119611
const sourceType = getTypeOfSymbol(sourceProp);
@@ -10439,7 +10439,7 @@ namespace ts {
1043910439
* Leave signatures alone since they are not subject to the check.
1044010440
*/
1044110441
function getRegularTypeOfObjectLiteral(type: Type): Type {
10442-
if (!(getObjectFlags(type) & ObjectFlags.ObjectLiteral && type.flags & TypeFlags.FreshLiteral)) {
10442+
if (!(isObjectLiteralType(type) && type.flags & TypeFlags.FreshLiteral)) {
1044310443
return type;
1044410444
}
1044510445
const regularType = (<FreshObjectLiteralType>type).regularType;
@@ -10469,7 +10469,7 @@ namespace ts {
1046910469
if (!context.siblings) {
1047010470
const siblings: Type[] = [];
1047110471
for (const type of getSiblingsOfContext(context.parent)) {
10472-
if (getObjectFlags(type) & ObjectFlags.ObjectLiteral) {
10472+
if (isObjectLiteralType(type)) {
1047310473
const prop = getPropertyOfObjectType(type, context.propertyName);
1047410474
if (prop) {
1047510475
forEachType(getTypeOfSymbol(prop), t => siblings.push(t));
@@ -10485,8 +10485,7 @@ namespace ts {
1048510485
if (!context.resolvedPropertyNames) {
1048610486
const names = createMap<boolean>() as UnderscoreEscapedMap<boolean>;
1048710487
for (const t of getSiblingsOfContext(context)) {
10488-
const objectFlags = getObjectFlags(t);
10489-
if (objectFlags & ObjectFlags.ObjectLiteral && !(objectFlags & ObjectFlags.ContainsSpread)) {
10488+
if (isObjectLiteralType(t) && !(getObjectFlags(t) & ObjectFlags.ContainsSpread)) {
1049010489
for (const prop of getPropertiesOfType(t)) {
1049110490
names.set(prop.escapedName, true);
1049210491
}
@@ -10545,7 +10544,7 @@ namespace ts {
1054510544
if (type.flags & TypeFlags.Nullable) {
1054610545
return anyType;
1054710546
}
10548-
if (getObjectFlags(type) & ObjectFlags.ObjectLiteral) {
10547+
if (isObjectLiteralType(type)) {
1054910548
return getWidenedTypeOfObjectLiteral(type, context);
1055010549
}
1055110550
if (type.flags & TypeFlags.Union) {
@@ -10586,7 +10585,7 @@ namespace ts {
1058610585
}
1058710586
}
1058810587
}
10589-
if (getObjectFlags(type) & ObjectFlags.ObjectLiteral) {
10588+
if (isObjectLiteralType(type)) {
1059010589
for (const p of getPropertiesOfObjectType(type)) {
1059110590
const t = getTypeOfSymbol(p);
1059210591
if (t.flags & TypeFlags.ContainsWideningType) {
@@ -11099,11 +11098,28 @@ namespace ts {
1109911098
return constraint && maybeTypeOfKind(constraint, TypeFlags.Primitive | TypeFlags.Index);
1110011099
}
1110111100

11101+
function isObjectLiteralType(type: Type) {
11102+
return !!(getObjectFlags(type) & ObjectFlags.ObjectLiteral);
11103+
}
11104+
11105+
function widenObjectLiteralCandidates(candidates: Type[]): Type[] {
11106+
if (candidates.length > 1) {
11107+
const objectLiterals = filter(candidates, isObjectLiteralType);
11108+
if (objectLiterals.length) {
11109+
const objectLiteralsType = getWidenedType(getUnionType(objectLiterals, /*subtypeReduction*/ true));
11110+
return concatenate(filter(candidates, t => !isObjectLiteralType(t)), [objectLiteralsType]);
11111+
}
11112+
}
11113+
return candidates;
11114+
}
11115+
1110211116
function getInferredType(context: InferenceContext, index: number): Type {
1110311117
const inference = context.inferences[index];
1110411118
let inferredType = inference.inferredType;
1110511119
if (!inferredType) {
1110611120
if (inference.candidates) {
11121+
// Extract all object literal types and replace them with a single widened and normalized type.
11122+
const candidates = widenObjectLiteralCandidates(inference.candidates);
1110711123
// We widen inferred literal types if
1110811124
// all inferences were made to top-level ocurrences of the type parameter, and
1110911125
// the type parameter has no constraint or its constraint includes no primitive or literal types, and
@@ -11112,7 +11128,7 @@ namespace ts {
1111211128
const widenLiteralTypes = inference.topLevel &&
1111311129
!hasPrimitiveConstraint(inference.typeParameter) &&
1111411130
(inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter));
11115-
const baseCandidates = widenLiteralTypes ? sameMap(inference.candidates, getWidenedLiteralType) : inference.candidates;
11131+
const baseCandidates = widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) : candidates;
1111611132
// If all inferences were made from contravariant positions, infer a common subtype. Otherwise, if
1111711133
// union types were requested or if all inferences were made from the return type position, infer a
1111811134
// union type. Otherwise, infer a common supertype.

0 commit comments

Comments
 (0)