@@ -11823,6 +11823,16 @@ namespace ts {
11823
11823
return hasNonCircularBaseConstraint(type) ? getConstraintFromConditionalType(type) : undefined;
11824
11824
}
11825
11825
11826
+ function hasStructuredOrInstantiableConstraint(type: Type) {
11827
+ const constraint = type.flags & TypeFlags.Instantiable ? getConstraintOfType(type) : undefined;
11828
+ return constraint && !!(constraint.flags & TypeFlags.StructuredOrInstantiable);
11829
+ }
11830
+
11831
+ function isUnionContainingMultipleObjectLikeTypes(type: Type) {
11832
+ return !!(type.flags & TypeFlags.Union) &&
11833
+ countWhere((type as UnionType).types, t => !!(t.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.Substitution))) >= 2;
11834
+ }
11835
+
11826
11836
function getEffectiveConstraintOfIntersection(types: readonly Type[], targetIsUnion: boolean) {
11827
11837
let constraints: Type[] | undefined;
11828
11838
let hasDisjointDomainType = false;
@@ -18346,18 +18356,27 @@ namespace ts {
18346
18356
let result = Ternary.False;
18347
18357
const saveErrorInfo = captureErrorCalculationState();
18348
18358
18349
- if (( source.flags & TypeFlags.Union || target.flags & TypeFlags.Union) && getConstituentCount(source) * getConstituentCount(target) < 4 ) {
18359
+ if (source.flags & TypeFlags.UnionOrIntersection || target.flags & TypeFlags.UnionOrIntersection ) {
18350
18360
// We skip caching when source or target is a union with no more than three constituents.
18351
- result = structuredTypeRelatedTo(source, target, reportErrors, intersectionState | IntersectionState.UnionIntersectionCheck);
18352
- }
18353
- else if (source.flags & TypeFlags.UnionOrIntersection || target.flags & TypeFlags.UnionOrIntersection) {
18354
- result = recursiveTypeRelatedTo(source, target, reportErrors, intersectionState | IntersectionState.UnionIntersectionCheck, recursionFlags);
18355
- }
18356
- if (!result && !(source.flags & TypeFlags.Union) && (source.flags & (TypeFlags.StructuredOrInstantiable) || target.flags & TypeFlags.StructuredOrInstantiable)) {
18357
- if (result = recursiveTypeRelatedTo(source, target, reportErrors, intersectionState, recursionFlags)) {
18358
- resetErrorInfo(saveErrorInfo);
18361
+ result = (source.flags & TypeFlags.Union || target.flags & TypeFlags.Union) && getConstituentCount(source) * getConstituentCount(target) < 4 ?
18362
+ structuredTypeRelatedTo(source, target, reportErrors, intersectionState | IntersectionState.UnionIntersectionCheck) :
18363
+ recursiveTypeRelatedTo(source, target, reportErrors, intersectionState | IntersectionState.UnionIntersectionCheck, recursionFlags);
18364
+ // The ordered decomposition above doesn't handle all cases. Specifically, we also need to handle:
18365
+ // (1) Source is an intersection of object types { a } & { b } and target is an object type { a, b }.
18366
+ // (2) Source is an object type { a, b: boolean } and target is a union { a, b: true } | { a, b: false }.
18367
+ // (3) Source is an intersection { a } & { b: boolean } and target is a union { a, b: true } | { a, b: false }.
18368
+ // (4) Source is an instantiable type with a union constraint and target is a union.
18369
+ if (!result && (source.flags & TypeFlags.Intersection && target.flags & TypeFlags.Object ||
18370
+ (source.flags & (TypeFlags.Object | TypeFlags.Intersection) && isUnionContainingMultipleObjectLikeTypes(target)) ||
18371
+ (target.flags & TypeFlags.Union && hasStructuredOrInstantiableConstraint(source)))) {
18372
+ if (result = recursiveTypeRelatedTo(source, target, reportErrors, intersectionState, recursionFlags)) {
18373
+ resetErrorInfo(saveErrorInfo);
18374
+ }
18359
18375
}
18360
18376
}
18377
+ else if (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable) {
18378
+ result = recursiveTypeRelatedTo(source, target, reportErrors, intersectionState, recursionFlags);
18379
+ }
18361
18380
if (!result && source.flags & (TypeFlags.Intersection | TypeFlags.TypeParameter)) {
18362
18381
// The combined constraint of an intersection type is the intersection of the constraints of
18363
18382
// the constituents. When an intersection type contains instantiable types with union type
@@ -18628,8 +18647,11 @@ namespace ts {
18628
18647
}
18629
18648
}
18630
18649
if (reportErrors) {
18650
+ // Elaborate only if we can find a best matching type in the target union
18631
18651
const bestMatchingType = getBestMatchingType(source, target, isRelatedTo);
18632
- isRelatedTo(source, bestMatchingType || targetTypes[targetTypes.length - 1], RecursionFlags.Target, /*reportErrors*/ true);
18652
+ if (bestMatchingType) {
18653
+ isRelatedTo(source, bestMatchingType, RecursionFlags.Target, /*reportErrors*/ true);
18654
+ }
18633
18655
}
18634
18656
return Ternary.False;
18635
18657
}
@@ -35937,34 +35959,26 @@ namespace ts {
35937
35959
return;
35938
35960
}
35939
35961
35962
+ let headMessage: DiagnosticMessage;
35940
35963
let expectedReturnType: Type;
35941
- const headMessage = getDiagnosticHeadMessageForDecoratorResolution(node);
35942
- let errorInfo: DiagnosticMessageChain | undefined;
35943
35964
switch (node.parent.kind) {
35944
35965
case SyntaxKind.ClassDeclaration:
35966
+ headMessage = Diagnostics.Decorator_function_return_type_0_is_not_assignable_to_type_1;
35945
35967
const classSymbol = getSymbolOfNode(node.parent);
35946
35968
const classConstructorType = getTypeOfSymbol(classSymbol);
35947
35969
expectedReturnType = getUnionType([classConstructorType, voidType]);
35948
35970
break;
35949
35971
35950
- case SyntaxKind.Parameter:
35951
- expectedReturnType = voidType;
35952
- errorInfo = chainDiagnosticMessages(
35953
- /*details*/ undefined,
35954
- Diagnostics.The_return_type_of_a_parameter_decorator_function_must_be_either_void_or_any);
35955
-
35956
- break;
35957
-
35958
35972
case SyntaxKind.PropertyDeclaration:
35973
+ case SyntaxKind.Parameter:
35974
+ headMessage = Diagnostics.Decorator_function_return_type_is_0_but_is_expected_to_be_void_or_any;
35959
35975
expectedReturnType = voidType;
35960
- errorInfo = chainDiagnosticMessages(
35961
- /*details*/ undefined,
35962
- Diagnostics.The_return_type_of_a_property_decorator_function_must_be_either_void_or_any);
35963
35976
break;
35964
35977
35965
35978
case SyntaxKind.MethodDeclaration:
35966
35979
case SyntaxKind.GetAccessor:
35967
35980
case SyntaxKind.SetAccessor:
35981
+ headMessage = Diagnostics.Decorator_function_return_type_0_is_not_assignable_to_type_1;
35968
35982
const methodType = getTypeOfNode(node.parent);
35969
35983
const descriptorType = createTypedPropertyDescriptorType(methodType);
35970
35984
expectedReturnType = getUnionType([descriptorType, voidType]);
@@ -35978,8 +35992,7 @@ namespace ts {
35978
35992
returnType,
35979
35993
expectedReturnType,
35980
35994
node,
35981
- headMessage,
35982
- () => errorInfo);
35995
+ headMessage);
35983
35996
}
35984
35997
35985
35998
/**
@@ -44217,27 +44230,26 @@ namespace ts {
44217
44230
44218
44231
function findMostOverlappyType(source: Type, unionTarget: UnionOrIntersectionType) {
44219
44232
let bestMatch: Type | undefined;
44220
- let matchingCount = 0;
44221
- for (const target of unionTarget.types) {
44222
- const overlap = getIntersectionType([getIndexType(source), getIndexType(target)]);
44223
- if (overlap.flags & TypeFlags.Index) {
44224
- // perfect overlap of keys
44225
- bestMatch = target;
44226
- matchingCount = Infinity;
44227
- }
44228
- else if (overlap.flags & TypeFlags.Union) {
44229
- // We only want to account for literal types otherwise.
44230
- // If we have a union of index types, it seems likely that we
44231
- // needed to elaborate between two generic mapped types anyway.
44232
- const len = length(filter((overlap as UnionType).types, isUnitType));
44233
- if (len >= matchingCount) {
44234
- bestMatch = target;
44235
- matchingCount = len;
44236
- }
44237
- }
44238
- else if (isUnitType(overlap) && 1 >= matchingCount) {
44239
- bestMatch = target;
44240
- matchingCount = 1;
44233
+ if (!(source.flags & (TypeFlags.Primitive | TypeFlags.InstantiablePrimitive))) {
44234
+ let matchingCount = 0;
44235
+ for (const target of unionTarget.types) {
44236
+ if (!(target.flags & (TypeFlags.Primitive | TypeFlags.InstantiablePrimitive))) {
44237
+ const overlap = getIntersectionType([getIndexType(source), getIndexType(target)]);
44238
+ if (overlap.flags & TypeFlags.Index) {
44239
+ // perfect overlap of keys
44240
+ return target;
44241
+ }
44242
+ else if (isUnitType(overlap) || overlap.flags & TypeFlags.Union) {
44243
+ // We only want to account for literal types otherwise.
44244
+ // If we have a union of index types, it seems likely that we
44245
+ // needed to elaborate between two generic mapped types anyway.
44246
+ const len = overlap.flags & TypeFlags.Union ? countWhere((overlap as UnionType).types, isUnitType) : 1;
44247
+ if (len >= matchingCount) {
44248
+ bestMatch = target;
44249
+ matchingCount = len;
44250
+ }
44251
+ }
44252
+ }
44241
44253
}
44242
44254
}
44243
44255
return bestMatch;
0 commit comments