@@ -183,10 +183,12 @@ namespace ts {
183
183
NoTupleBoundsCheck = 1 << 3,
184
184
}
185
185
186
- const enum CallbackCheck {
187
- None,
188
- Bivariant,
189
- Strict,
186
+ const enum SignatureCheckMode {
187
+ BivariantCallback = 1 << 0,
188
+ StrictCallback = 1 << 1,
189
+ IgnoreReturnTypes = 1 << 2,
190
+ StrictArity = 1 << 3,
191
+ Callback = BivariantCallback | StrictCallback,
190
192
}
191
193
192
194
const enum MappedTypeModifiers {
@@ -343,6 +345,7 @@ namespace ts {
343
345
assignable: assignableRelation.size,
344
346
identity: identityRelation.size,
345
347
subtype: subtypeRelation.size,
348
+ strictSubtype: strictSubtypeRelation.size,
346
349
}),
347
350
isUndefinedSymbol: symbol => symbol === undefinedSymbol,
348
351
isArgumentsSymbol: symbol => symbol === argumentsSymbol,
@@ -869,6 +872,7 @@ namespace ts {
869
872
let outofbandVarianceMarkerHandler: ((onlyUnreliable: boolean) => void) | undefined;
870
873
871
874
const subtypeRelation = createMap<RelationComparisonResult>();
875
+ const strictSubtypeRelation = createMap<RelationComparisonResult>();
872
876
const assignableRelation = createMap<RelationComparisonResult>();
873
877
const comparableRelation = createMap<RelationComparisonResult>();
874
878
const identityRelation = createMap<RelationComparisonResult>();
@@ -11428,7 +11432,7 @@ namespace ts {
11428
11432
}
11429
11433
}
11430
11434
count++;
11431
- if (isTypeSubtypeOf (source, target) && (
11435
+ if (isTypeRelatedTo (source, target, strictSubtypeRelation ) && (
11432
11436
!(getObjectFlags(getTargetType(source)) & ObjectFlags.Class) ||
11433
11437
!(getObjectFlags(getTargetType(target)) & ObjectFlags.Class) ||
11434
11438
isTypeDerivedFrom(source, target))) {
@@ -14016,7 +14020,7 @@ namespace ts {
14016
14020
function isSignatureAssignableTo(source: Signature,
14017
14021
target: Signature,
14018
14022
ignoreReturnTypes: boolean): boolean {
14019
- return compareSignaturesRelated(source, target, CallbackCheck.None, ignoreReturnTypes , /*reportErrors*/ false,
14023
+ return compareSignaturesRelated(source, target, ignoreReturnTypes ? SignatureCheckMode.IgnoreReturnTypes : 0 , /*reportErrors*/ false,
14020
14024
/*errorReporter*/ undefined, /*errorReporter*/ undefined, compareTypesAssignable, /*reportUnreliableMarkers*/ undefined) !== Ternary.False;
14021
14025
}
14022
14026
@@ -14036,8 +14040,7 @@ namespace ts {
14036
14040
*/
14037
14041
function compareSignaturesRelated(source: Signature,
14038
14042
target: Signature,
14039
- callbackCheck: CallbackCheck,
14040
- ignoreReturnTypes: boolean,
14043
+ checkMode: SignatureCheckMode,
14041
14044
reportErrors: boolean,
14042
14045
errorReporter: ErrorReporter | undefined,
14043
14046
incompatibleErrorReporter: ((source: Type, target: Type) => void) | undefined,
@@ -14053,7 +14056,9 @@ namespace ts {
14053
14056
}
14054
14057
14055
14058
const targetCount = getParameterCount(target);
14056
- if (!hasEffectiveRestParameter(target) && getMinArgumentCount(source) > targetCount) {
14059
+ const sourceHasMoreParameters = !hasEffectiveRestParameter(target) &&
14060
+ (checkMode & SignatureCheckMode.StrictArity ? hasEffectiveRestParameter(source) || getParameterCount(source) > targetCount : getMinArgumentCount(source) > targetCount);
14061
+ if (sourceHasMoreParameters) {
14057
14062
return Ternary.False;
14058
14063
}
14059
14064
@@ -14074,7 +14079,7 @@ namespace ts {
14074
14079
}
14075
14080
14076
14081
const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown;
14077
- const strictVariance = !callbackCheck && strictFunctionTypes && kind !== SyntaxKind.MethodDeclaration &&
14082
+ const strictVariance = !(checkMode & SignatureCheckMode.Callback) && strictFunctionTypes && kind !== SyntaxKind.MethodDeclaration &&
14078
14083
kind !== SyntaxKind.MethodSignature && kind !== SyntaxKind.Constructor;
14079
14084
let result = Ternary.True;
14080
14085
@@ -14109,14 +14114,17 @@ namespace ts {
14109
14114
// similar to return values, callback parameters are output positions. This means that a Promise<T>,
14110
14115
// where T is used only in callback parameter positions, will be co-variant (as opposed to bi-variant)
14111
14116
// with respect to T.
14112
- const sourceSig = callbackCheck ? undefined : getSingleCallSignature(getNonNullableType(sourceType));
14113
- const targetSig = callbackCheck ? undefined : getSingleCallSignature(getNonNullableType(targetType));
14117
+ const sourceSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(sourceType));
14118
+ const targetSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(targetType));
14114
14119
const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) &&
14115
14120
(getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable);
14116
- const related = callbacks ?
14117
- // TODO: GH#18217 It will work if they're both `undefined`, but not if only one is
14118
- compareSignaturesRelated(targetSig!, sourceSig!, strictVariance ? CallbackCheck.Strict : CallbackCheck.Bivariant, /*ignoreReturnTypes*/ false, reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers) :
14119
- !callbackCheck && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors);
14121
+ let related = callbacks ?
14122
+ compareSignaturesRelated(targetSig!, sourceSig!, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers) :
14123
+ !(checkMode & SignatureCheckMode.Callback) && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors);
14124
+ // With strict arity, (x: number | undefined) => void is a subtype of (x?: number | undefined) => void
14125
+ if (related && checkMode & SignatureCheckMode.StrictArity && i >= getMinArgumentCount(source) && i < getMinArgumentCount(target) && compareTypes(sourceType, targetType, /*reportErrors*/ false)) {
14126
+ related = Ternary.False;
14127
+ }
14120
14128
if (!related) {
14121
14129
if (reportErrors) {
14122
14130
errorReporter!(Diagnostics.Types_of_parameters_0_and_1_are_incompatible,
@@ -14128,7 +14136,7 @@ namespace ts {
14128
14136
result &= related;
14129
14137
}
14130
14138
14131
- if (!ignoreReturnTypes ) {
14139
+ if (!(checkMode & SignatureCheckMode.IgnoreReturnTypes) ) {
14132
14140
// If a signature resolution is already in-flight, skip issuing a circularity error
14133
14141
// here and just use the `any` type directly
14134
14142
const targetReturnType = isResolvingReturnTypeOfSignature(target) ? anyType
@@ -14159,7 +14167,7 @@ namespace ts {
14159
14167
// When relating callback signatures, we still need to relate return types bi-variantly as otherwise
14160
14168
// the containing type wouldn't be co-variant. For example, interface Foo<T> { add(cb: () => T): void }
14161
14169
// wouldn't be co-variant for T without this rule.
14162
- result &= callbackCheck === CallbackCheck.Bivariant && compareTypes(targetReturnType, sourceReturnType, /*reportErrors*/ false) ||
14170
+ result &= checkMode & SignatureCheckMode.BivariantCallback && compareTypes(targetReturnType, sourceReturnType, /*reportErrors*/ false) ||
14163
14171
compareTypes(sourceReturnType, targetReturnType, reportErrors);
14164
14172
if (!result && reportErrors && incompatibleErrorReporter) {
14165
14173
incompatibleErrorReporter(sourceReturnType, targetReturnType);
@@ -15467,7 +15475,7 @@ namespace ts {
15467
15475
}
15468
15476
else {
15469
15477
// An empty object type is related to any mapped type that includes a '?' modifier.
15470
- if (relation !== subtypeRelation && isPartialMappedType(target) && isEmptyObjectType(source)) {
15478
+ if (relation !== subtypeRelation && relation !== strictSubtypeRelation && isPartialMappedType(target) && isEmptyObjectType(source)) {
15471
15479
return Ternary.True;
15472
15480
}
15473
15481
if (isGenericMappedType(target)) {
@@ -15509,7 +15517,7 @@ namespace ts {
15509
15517
}
15510
15518
// Consider a fresh empty object literal type "closed" under the subtype relationship - this way `{} <- {[idx: string]: any} <- fresh({})`
15511
15519
// and not `{} <- fresh({}) <- {[idx: string]: any}`
15512
- else if (relation === subtypeRelation && isEmptyObjectType(target) && getObjectFlags(target) & ObjectFlags.FreshLiteral && !isEmptyObjectType(source)) {
15520
+ else if (( relation === subtypeRelation || relation === strictSubtypeRelation) && isEmptyObjectType(target) && getObjectFlags(target) & ObjectFlags.FreshLiteral && !isEmptyObjectType(source)) {
15513
15521
return Ternary.False;
15514
15522
}
15515
15523
// Even if relationship doesn't hold for unions, intersections, or generic type references,
@@ -15854,7 +15862,7 @@ namespace ts {
15854
15862
if (relation === identityRelation) {
15855
15863
return propertiesIdenticalTo(source, target, excludedProperties);
15856
15864
}
15857
- const requireOptionalProperties = relation === subtypeRelation && !isObjectLiteralType(source) && !isEmptyArrayLiteralType(source) && !isTupleType(source);
15865
+ const requireOptionalProperties = ( relation === subtypeRelation || relation === strictSubtypeRelation) && !isObjectLiteralType(source) && !isEmptyArrayLiteralType(source) && !isTupleType(source);
15858
15866
const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false);
15859
15867
if (unmatchedProperty) {
15860
15868
if (reportErrors) {
@@ -16077,7 +16085,7 @@ namespace ts {
16077
16085
*/
16078
16086
function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean, incompatibleReporter: (source: Type, target: Type) => void): Ternary {
16079
16087
return compareSignaturesRelated(erase ? getErasedSignature(source) : source, erase ? getErasedSignature(target) : target,
16080
- CallbackCheck.None, /*ignoreReturnTypes*/ false , reportErrors, reportError, incompatibleReporter, isRelatedTo, reportUnreliableMarkers);
16088
+ relation === strictSubtypeRelation ? SignatureCheckMode.StrictArity : 0 , reportErrors, reportError, incompatibleReporter, isRelatedTo, reportUnreliableMarkers);
16081
16089
}
16082
16090
16083
16091
function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary {
@@ -16391,12 +16399,12 @@ namespace ts {
16391
16399
source = target;
16392
16400
target = temp;
16393
16401
}
16394
- const intersection = isIntersectionConstituent ? "& " : "";
16402
+ const delimiter = isIntersectionConstituent ? "; " : ", ";
16395
16403
if (isTypeReferenceWithGenericArguments(source) && isTypeReferenceWithGenericArguments(target)) {
16396
16404
const typeParameters: Type[] = [];
16397
- return getTypeReferenceId(<TypeReference>source, typeParameters) + "," + getTypeReferenceId(<TypeReference>target, typeParameters) + intersection ;
16405
+ return getTypeReferenceId(<TypeReference>source, typeParameters) + delimiter + getTypeReferenceId(<TypeReference>target, typeParameters);
16398
16406
}
16399
- return source.id + "," + target.id + intersection ;
16407
+ return source.id + delimiter + target.id;
16400
16408
}
16401
16409
16402
16410
// Invoke the callback for each underlying property symbol of the given symbol and return the first
0 commit comments