@@ -3507,7 +3507,7 @@ namespace ts {
3507
3507
3508
3508
function findMatchingSignature(signatureList: Signature[], signature: Signature, partialMatch: boolean, ignoreReturnTypes: boolean): Signature {
3509
3509
for (const s of signatureList) {
3510
- if (compareSignatures (s, signature, partialMatch, ignoreReturnTypes, compareTypes )) {
3510
+ if (compareSignaturesIdentical (s, signature, partialMatch, ignoreReturnTypes, compareTypesIdentical )) {
3511
3511
return s;
3512
3512
}
3513
3513
}
@@ -3768,11 +3768,14 @@ namespace ts {
3768
3768
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: string): Symbol {
3769
3769
const types = containingType.types;
3770
3770
let props: Symbol[];
3771
+ // Flags we want to propagate to the result if they exist in all source symbols
3772
+ let commonFlags = (containingType.flags & TypeFlags.Intersection) ? SymbolFlags.Optional : SymbolFlags.None;
3771
3773
for (const current of types) {
3772
3774
const type = getApparentType(current);
3773
3775
if (type !== unknownType) {
3774
3776
const prop = getPropertyOfType(type, name);
3775
3777
if (prop && !(getDeclarationFlagsFromSymbol(prop) & (NodeFlags.Private | NodeFlags.Protected))) {
3778
+ commonFlags &= prop.flags;
3776
3779
if (!props) {
3777
3780
props = [prop];
3778
3781
}
@@ -3800,7 +3803,12 @@ namespace ts {
3800
3803
}
3801
3804
propTypes.push(getTypeOfSymbol(prop));
3802
3805
}
3803
- const result = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.SyntheticProperty, name);
3806
+ const result = <TransientSymbol>createSymbol(
3807
+ SymbolFlags.Property |
3808
+ SymbolFlags.Transient |
3809
+ SymbolFlags.SyntheticProperty |
3810
+ commonFlags,
3811
+ name);
3804
3812
result.containingType = containingType;
3805
3813
result.declarations = declarations;
3806
3814
result.type = containingType.flags & TypeFlags.Union ? getUnionType(propTypes) : getIntersectionType(propTypes);
@@ -4959,7 +4967,7 @@ namespace ts {
4959
4967
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined);
4960
4968
}
4961
4969
4962
- function compareTypes (source: Type, target: Type): Ternary {
4970
+ function compareTypesIdentical (source: Type, target: Type): Ternary {
4963
4971
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined) ? Ternary.True : Ternary.False;
4964
4972
}
4965
4973
@@ -4979,10 +4987,96 @@ namespace ts {
4979
4987
return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage, containingMessageChain);
4980
4988
}
4981
4989
4982
- function isSignatureAssignableTo(source: Signature, target: Signature): boolean {
4983
- const sourceType = getOrCreateTypeFromSignature(source);
4984
- const targetType = getOrCreateTypeFromSignature(target);
4985
- return checkTypeRelatedTo(sourceType, targetType, assignableRelation, /*errorNode*/ undefined);
4990
+ /**
4991
+ * See signatureRelatedTo, compareSignaturesIdentical
4992
+ */
4993
+ function isSignatureAssignableTo(source: Signature, target: Signature, ignoreReturnTypes: boolean): boolean {
4994
+ // TODO (drosen): De-duplicate code between related functions.
4995
+ if (source === target) {
4996
+ return true;
4997
+ }
4998
+ if (!target.hasRestParameter && source.minArgumentCount > target.parameters.length) {
4999
+ return false;
5000
+ }
5001
+
5002
+ // Spec 1.0 Section 3.8.3 & 3.8.4:
5003
+ // M and N (the signatures) are instantiated using type Any as the type argument for all type parameters declared by M and N
5004
+ source = getErasedSignature(source);
5005
+ target = getErasedSignature(target);
5006
+
5007
+ const sourceMax = getNumNonRestParameters(source);
5008
+ const targetMax = getNumNonRestParameters(target);
5009
+ const checkCount = getNumParametersToCheckForSignatureRelatability(source, sourceMax, target, targetMax);
5010
+ for (let i = 0; i < checkCount; i++) {
5011
+ const s = i < sourceMax ? getTypeOfSymbol(source.parameters[i]) : getRestTypeOfSignature(source);
5012
+ const t = i < targetMax ? getTypeOfSymbol(target.parameters[i]) : getRestTypeOfSignature(target);
5013
+ const related = isTypeAssignableTo(t, s) || isTypeAssignableTo(s, t);
5014
+ if (!related) {
5015
+ return false;
5016
+ }
5017
+ }
5018
+
5019
+ if (!ignoreReturnTypes) {
5020
+ const targetReturnType = getReturnTypeOfSignature(target);
5021
+ if (targetReturnType === voidType) {
5022
+ return true;
5023
+ }
5024
+ const sourceReturnType = getReturnTypeOfSignature(source);
5025
+
5026
+ // The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions
5027
+ if (targetReturnType.flags & TypeFlags.PredicateType && (targetReturnType as PredicateType).predicate.kind === TypePredicateKind.Identifier) {
5028
+ if (!(sourceReturnType.flags & TypeFlags.PredicateType)) {
5029
+ return false;
5030
+ }
5031
+ }
5032
+
5033
+ return isTypeAssignableTo(sourceReturnType, targetReturnType);
5034
+ }
5035
+
5036
+ return true;
5037
+ }
5038
+
5039
+ function isImplementationCompatibleWithOverload(implementation: Signature, overload: Signature): boolean {
5040
+ const erasedSource = getErasedSignature(implementation);
5041
+ const erasedTarget = getErasedSignature(overload);
5042
+
5043
+ // First see if the return types are compatible in either direction.
5044
+ const sourceReturnType = getReturnTypeOfSignature(erasedSource);
5045
+ const targetReturnType = getReturnTypeOfSignature(erasedTarget);
5046
+ if (targetReturnType === voidType
5047
+ || checkTypeRelatedTo(targetReturnType, sourceReturnType, assignableRelation, /*errorNode*/ undefined)
5048
+ || checkTypeRelatedTo(sourceReturnType, targetReturnType, assignableRelation, /*errorNode*/ undefined)) {
5049
+
5050
+ return isSignatureAssignableTo(erasedSource, erasedTarget, /*ignoreReturnTypes*/ true);
5051
+ }
5052
+
5053
+ return false;
5054
+ }
5055
+
5056
+ function getNumNonRestParameters(signature: Signature) {
5057
+ const numParams = signature.parameters.length;
5058
+ return signature.hasRestParameter ?
5059
+ numParams - 1 :
5060
+ numParams;
5061
+ }
5062
+
5063
+ function getNumParametersToCheckForSignatureRelatability(source: Signature, sourceNonRestParamCount: number, target: Signature, targetNonRestParamCount: number) {
5064
+ if (source.hasRestParameter === target.hasRestParameter) {
5065
+ if (source.hasRestParameter) {
5066
+ // If both have rest parameters, get the max and add 1 to
5067
+ // compensate for the rest parameter.
5068
+ return Math.max(sourceNonRestParamCount, targetNonRestParamCount) + 1;
5069
+ }
5070
+ else {
5071
+ return Math.min(sourceNonRestParamCount, targetNonRestParamCount);
5072
+ }
5073
+ }
5074
+ else {
5075
+ // Return the count for whichever signature doesn't have rest parameters.
5076
+ return source.hasRestParameter ?
5077
+ targetNonRestParamCount :
5078
+ sourceNonRestParamCount;
5079
+ }
4986
5080
}
4987
5081
4988
5082
/**
@@ -5574,7 +5668,7 @@ namespace ts {
5574
5668
shouldElaborateErrors = false;
5575
5669
}
5576
5670
}
5577
- // don't elaborate the primitive apparent types (like Number)
5671
+ // don't elaborate the primitive apparent types (like Number)
5578
5672
// because the actual primitives will have already been reported.
5579
5673
if (shouldElaborateErrors && !isPrimitiveApparentType(source)) {
5580
5674
reportError(Diagnostics.Type_0_provides_no_match_for_the_signature_1,
@@ -5621,7 +5715,11 @@ namespace ts {
5621
5715
}
5622
5716
}
5623
5717
5718
+ /**
5719
+ * See signatureAssignableTo, signatureAssignableTo
5720
+ */
5624
5721
function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean): Ternary {
5722
+ // TODO (drosen): De-duplicate code between related functions.
5625
5723
if (source === target) {
5626
5724
return Ternary.True;
5627
5725
}
@@ -5673,10 +5771,12 @@ namespace ts {
5673
5771
}
5674
5772
5675
5773
const targetReturnType = getReturnTypeOfSignature(target);
5676
- if (targetReturnType === voidType) return result;
5774
+ if (targetReturnType === voidType) {
5775
+ return result;
5776
+ }
5677
5777
const sourceReturnType = getReturnTypeOfSignature(source);
5678
5778
5679
- // The follow block preserves old behavior forbidding boolean returning functions from being assignable to type guard returning functions
5779
+ // The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions
5680
5780
if (targetReturnType.flags & TypeFlags.PredicateType && (targetReturnType as PredicateType).predicate.kind === TypePredicateKind.Identifier) {
5681
5781
if (!(sourceReturnType.flags & TypeFlags.PredicateType)) {
5682
5782
if (reportErrors) {
@@ -5697,7 +5797,7 @@ namespace ts {
5697
5797
}
5698
5798
let result = Ternary.True;
5699
5799
for (let i = 0, len = sourceSignatures.length; i < len; ++i) {
5700
- const related = compareSignatures (sourceSignatures[i], targetSignatures[i], /*partialMatch*/ false, /*ignoreReturnTypes*/ false, isRelatedTo);
5800
+ const related = compareSignaturesIdentical (sourceSignatures[i], targetSignatures[i], /*partialMatch*/ false, /*ignoreReturnTypes*/ false, isRelatedTo);
5701
5801
if (!related) {
5702
5802
return Ternary.False;
5703
5803
}
@@ -5830,7 +5930,7 @@ namespace ts {
5830
5930
}
5831
5931
5832
5932
function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean {
5833
- return compareProperties(sourceProp, targetProp, compareTypes ) !== Ternary.False;
5933
+ return compareProperties(sourceProp, targetProp, compareTypesIdentical ) !== Ternary.False;
5834
5934
}
5835
5935
5836
5936
function compareProperties(sourceProp: Symbol, targetProp: Symbol, compareTypes: (source: Type, target: Type) => Ternary): Ternary {
@@ -5877,7 +5977,11 @@ namespace ts {
5877
5977
return false;
5878
5978
}
5879
5979
5880
- function compareSignatures(source: Signature, target: Signature, partialMatch: boolean, ignoreReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary {
5980
+ /**
5981
+ * See signatureRelatedTo, compareSignaturesIdentical
5982
+ */
5983
+ function compareSignaturesIdentical(source: Signature, target: Signature, partialMatch: boolean, ignoreReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary {
5984
+ // TODO (drosen): De-duplicate code between related functions.
5881
5985
if (source === target) {
5882
5986
return Ternary.True;
5883
5987
}
@@ -7605,7 +7709,7 @@ namespace ts {
7605
7709
// This signature will contribute to contextual union signature
7606
7710
signatureList = [signature];
7607
7711
}
7608
- else if (!compareSignatures (signatureList[0], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true, compareTypes )) {
7712
+ else if (!compareSignaturesIdentical (signatureList[0], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true, compareTypesIdentical )) {
7609
7713
// Signatures aren't identical, do not use
7610
7714
return undefined;
7611
7715
}
@@ -8280,9 +8384,9 @@ namespace ts {
8280
8384
// Props is of type 'any' or unknown
8281
8385
return links.resolvedJsxType = attributesType;
8282
8386
}
8283
- else if (!( attributesType.flags & TypeFlags.ObjectType) ) {
8284
- // Props is not an object type
8285
- error(node.tagName, Diagnostics.JSX_element_attributes_type_0_must_be_an_object_type , typeToString(attributesType));
8387
+ else if (attributesType.flags & TypeFlags.Union ) {
8388
+ // Props cannot be a union type
8389
+ error(node.tagName, Diagnostics.JSX_element_attributes_type_0_may_not_be_a_union_type , typeToString(attributesType));
8286
8390
return links.resolvedJsxType = anyType;
8287
8391
}
8288
8392
else {
@@ -11626,7 +11730,7 @@ namespace ts {
11626
11730
}
11627
11731
11628
11732
for (const otherSignature of signaturesToCheck) {
11629
- if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature)) {
11733
+ if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature, /*ignoreReturnTypes*/ false )) {
11630
11734
return;
11631
11735
}
11632
11736
}
@@ -11873,7 +11977,7 @@ namespace ts {
11873
11977
//
11874
11978
// The implementation is completely unrelated to the specialized signature, yet we do not check this.
11875
11979
for (const signature of signatures) {
11876
- if (!signature.hasStringLiterals && !isSignatureAssignableTo (bodySignature, signature)) {
11980
+ if (!signature.hasStringLiterals && !isImplementationCompatibleWithOverload (bodySignature, signature)) {
11877
11981
error(signature.declaration, Diagnostics.Overload_signature_is_not_compatible_with_function_implementation);
11878
11982
break;
11879
11983
}
0 commit comments