@@ -9786,31 +9786,29 @@ namespace ts {
97869786 if (checkType === wildcardType || extendsType === wildcardType) {
97879787 return wildcardType;
97889788 }
9789- // If this is a distributive conditional type and the check type is generic we need to defer
9790- // resolution of the conditional type such that a later instantiation will properly distribute
9791- // over union types.
9792- const isDeferred = root.isDistributive && maybeTypeOfKind(checkType, TypeFlags.Instantiable);
9789+ const checkTypeInstantiable = maybeTypeOfKind(checkType, TypeFlags.Instantiable);
97939790 let combinedMapper: TypeMapper | undefined;
97949791 if (root.inferTypeParameters) {
97959792 const context = createInferenceContext(root.inferTypeParameters, /*signature*/ undefined, InferenceFlags.None);
9796- if (!isDeferred ) {
9793+ if (!checkTypeInstantiable ) {
97979794 // We don't want inferences from constraints as they may cause us to eagerly resolve the
97989795 // conditional type instead of deferring resolution. Also, we always want strict function
97999796 // types rules (i.e. proper contravariance) for inferences.
98009797 inferTypes(context.inferences, checkType, extendsType, InferencePriority.NoConstraints | InferencePriority.AlwaysStrict);
98019798 }
98029799 combinedMapper = combineTypeMappers(mapper, context);
98039800 }
9804- if (!isDeferred) {
9805- if (extendsType.flags & TypeFlags.AnyOrUnknown) {
9801+ // Instantiate the extends type including inferences for 'infer T' type parameters
9802+ const inferredExtendsType = combinedMapper ? instantiateType(root.extendsType, combinedMapper) : extendsType;
9803+ // We attempt to resolve the conditional type only when the check and extends types are non-generic
9804+ if (!checkTypeInstantiable && !maybeTypeOfKind(inferredExtendsType, TypeFlags.Instantiable)) {
9805+ if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown) {
98069806 return instantiateType(root.trueType, mapper);
98079807 }
98089808 // Return union of trueType and falseType for 'any' since it matches anything
98099809 if (checkType.flags & TypeFlags.Any) {
98109810 return getUnionType([instantiateType(root.trueType, combinedMapper || mapper), instantiateType(root.falseType, mapper)]);
98119811 }
9812- // Instantiate the extends type including inferences for 'infer T' type parameters
9813- const inferredExtendsType = combinedMapper ? instantiateType(root.extendsType, combinedMapper) : extendsType;
98149812 // Return falseType for a definitely false extends check. We check an instantations of the two
98159813 // types with type parameters mapped to the wildcard type, the most permissive instantiations
98169814 // possible (the wildcard type is assignable to and from all types). If those are not related,
@@ -11838,7 +11836,7 @@ namespace ts {
1183811836 if (!noImplicitAny && getObjectFlags(target) & ObjectFlags.JSLiteral) {
1183911837 return false; // Disable excess property checks on JS literals to simulate having an implicit "index signature" - but only outside of noImplicitAny
1184011838 }
11841- if (maybeTypeOfKind (target, TypeFlags.Object) && !(getObjectFlags(target) & ObjectFlags.ObjectLiteralPatternWithComputedProperties )) {
11839+ if (isExcessPropertyCheckTarget (target)) {
1184211840 const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes);
1184311841 if ((relation === assignableRelation || relation === definitelyAssignableRelation || relation === comparableRelation) &&
1184411842 (isTypeSubsetOf(globalObjectType, target) || (!isComparingJsxAttributes && isEmptyObjectType(target)))) {
@@ -11851,6 +11849,9 @@ namespace ts {
1185111849 for (const prop of getPropertiesOfObjectType(source)) {
1185211850 if (shouldCheckAsExcessProperty(prop, source.symbol) && !isKnownProperty(target, prop.escapedName, isComparingJsxAttributes)) {
1185311851 if (reportErrors) {
11852+ // Report error in terms of object types in the target as those are the only ones
11853+ // we check in isKnownProperty.
11854+ const errorTarget = filterType(target, isExcessPropertyCheckTarget);
1185411855 // We know *exactly* where things went wrong when comparing the types.
1185511856 // Use this property as the error node as this will be more helpful in
1185611857 // reasoning about what went wrong.
@@ -11859,7 +11860,7 @@ namespace ts {
1185911860 // JsxAttributes has an object-literal flag and undergo same type-assignablity check as normal object-literal.
1186011861 // However, using an object-literal error message will be very confusing to the users so we give different a message.
1186111862 // TODO: Spelling suggestions for excess jsx attributes (needs new diagnostic messages)
11862- reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(prop), typeToString(target ));
11863+ reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(prop), typeToString(errorTarget ));
1186311864 }
1186411865 else {
1186511866 // use the property's value declaration if the property is assigned inside the literal itself
@@ -11873,17 +11874,17 @@ namespace ts {
1187311874
1187411875 const name = propDeclaration.name!;
1187511876 if (isIdentifier(name)) {
11876- suggestion = getSuggestionForNonexistentProperty(name, target );
11877+ suggestion = getSuggestionForNonexistentProperty(name, errorTarget );
1187711878 }
1187811879 }
1187911880
1188011881 if (suggestion !== undefined) {
1188111882 reportError(Diagnostics.Object_literal_may_only_specify_known_properties_but_0_does_not_exist_in_type_1_Did_you_mean_to_write_2,
11882- symbolToString(prop), typeToString(target ), suggestion);
11883+ symbolToString(prop), typeToString(errorTarget ), suggestion);
1188311884 }
1188411885 else {
1188511886 reportError(Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1,
11886- symbolToString(prop), typeToString(target ));
11887+ symbolToString(prop), typeToString(errorTarget ));
1188711888 }
1188811889 }
1188911890 }
@@ -14616,15 +14617,15 @@ namespace ts {
1461614617 getAccessedPropertyName(source as PropertyAccessExpression | ElementAccessExpression) === getAccessedPropertyName(target) &&
1461714618 isMatchingReference((source as PropertyAccessExpression | ElementAccessExpression).expression, target.expression);
1461814619 case SyntaxKind.BindingElement:
14619- if (target.kind !== SyntaxKind.PropertyAccessExpression) return false;
14620- const t = target as PropertyAccessExpression ;
14621- if (t.name.escapedText !== getBindingElementNameText(source as BindingElement)) return false;
14622- if (source.parent.parent.kind === SyntaxKind.BindingElement && isMatchingReference(source.parent.parent, t .expression)) {
14623- return true;
14624- }
14625- if (source.parent.parent.kind === SyntaxKind. VariableDeclaration) {
14626- const maybeId = (source.parent.parent as VariableDeclaration).initializer ;
14627- return !!maybeId && isMatchingReference(maybeId, t.expression);
14620+ if (target.kind === SyntaxKind.PropertyAccessExpression && (<PropertyAccessExpression>target).name.escapedText === getBindingElementNameText(<BindingElement>source)) {
14621+ const ancestor = source.parent.parent ;
14622+ if (ancestor.kind === SyntaxKind. BindingElement) {
14623+ return isMatchingReference(ancestor, (<PropertyAccessExpression>target) .expression);
14624+ }
14625+ if (ancestor.kind === SyntaxKind.VariableDeclaration) {
14626+ const initializer = (< VariableDeclaration>ancestor).initializer;
14627+ return !!initializer && isMatchingReference(initializer, (<PropertyAccessExpression>target).expression) ;
14628+ }
1462814629 }
1462914630 }
1463014631 return false;
@@ -14636,14 +14637,25 @@ namespace ts {
1463614637 undefined;
1463714638 }
1463814639
14640+ function getReferenceParent(source: Node) {
14641+ if (source.kind === SyntaxKind.PropertyAccessExpression) {
14642+ return (<PropertyAccessExpression>source).expression;
14643+ }
14644+ if (source.kind === SyntaxKind.BindingElement) {
14645+ const ancestor = source.parent.parent;
14646+ return ancestor.kind === SyntaxKind.VariableDeclaration ? (<VariableDeclaration>ancestor).initializer : ancestor;
14647+ }
14648+ return undefined;
14649+ }
14650+
1463914651 function containsMatchingReference(source: Node, target: Node) {
14640- while (source.kind === SyntaxKind.PropertyAccessExpression) {
14641- source = (<PropertyAccessExpression>source).expression;
14642- if (isMatchingReference(source , target)) {
14652+ let parent = getReferenceParent(source);
14653+ while (parent) {
14654+ if (isMatchingReference(parent , target)) {
1464314655 return true;
1464414656 }
14657+ parent = getReferenceParent(parent);
1464514658 }
14646- return false;
1464714659 }
1464814660
1464914661 // Return true if target is a property access xxx.yyy, source is a property access xxx.zzz, the declared
@@ -18585,20 +18597,23 @@ namespace ts {
1858518597 return true;
1858618598 }
1858718599 }
18588- else if (targetType.flags & TypeFlags.UnionOrIntersection) {
18600+ else if (targetType.flags & TypeFlags.UnionOrIntersection && isExcessPropertyCheckTarget(targetType) ) {
1858918601 for (const t of (targetType as UnionOrIntersectionType).types) {
1859018602 if (isKnownProperty(t, name, isComparingJsxAttributes)) {
1859118603 return true;
1859218604 }
1859318605 }
1859418606 }
18595- else if (targetType.flags & TypeFlags.Conditional) {
18596- return isKnownProperty((targetType as ConditionalType).root.trueType, name, isComparingJsxAttributes) ||
18597- isKnownProperty((targetType as ConditionalType).root.falseType, name, isComparingJsxAttributes);
18598- }
1859918607 return false;
1860018608 }
1860118609
18610+ function isExcessPropertyCheckTarget(type: Type): boolean {
18611+ return !!(type.flags & TypeFlags.Object && !(getObjectFlags(type) & ObjectFlags.ObjectLiteralPatternWithComputedProperties) ||
18612+ type.flags & TypeFlags.NonPrimitive ||
18613+ type.flags & TypeFlags.Union && some((<UnionType>type).types, isExcessPropertyCheckTarget) ||
18614+ type.flags & TypeFlags.Intersection && every((<IntersectionType>type).types, isExcessPropertyCheckTarget));
18615+ }
18616+
1860218617 function checkJsxExpression(node: JsxExpression, checkMode?: CheckMode) {
1860318618 if (node.expression) {
1860418619 const type = checkExpression(node.expression, checkMode);
0 commit comments