@@ -871,6 +871,7 @@ namespace ts {
871
871
let outofbandVarianceMarkerHandler: ((onlyUnreliable: boolean) => void) | undefined;
872
872
873
873
const subtypeRelation = createMap<RelationComparisonResult>();
874
+ const strictSubtypeRelation = createMap<RelationComparisonResult>();
874
875
const assignableRelation = createMap<RelationComparisonResult>();
875
876
const comparableRelation = createMap<RelationComparisonResult>();
876
877
const identityRelation = createMap<RelationComparisonResult>();
@@ -11398,7 +11399,7 @@ namespace ts {
11398
11399
}
11399
11400
}
11400
11401
count++;
11401
- if (isTypeSubtypeOf (source, target) && (
11402
+ if (isTypeRelatedTo (source, target, strictSubtypeRelation ) && (
11402
11403
!(getObjectFlags(getTargetType(source)) & ObjectFlags.Class) ||
11403
11404
!(getObjectFlags(getTargetType(target)) & ObjectFlags.Class) ||
11404
11405
isTypeDerivedFrom(source, target))) {
@@ -14301,7 +14302,7 @@ namespace ts {
14301
14302
return true;
14302
14303
}
14303
14304
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) {
14304
- const related = relation.get(getRelationKey(source, target, /*isIntersectionConstituent*/ false, /*strictArityChecks*/ false, relation));
14305
+ const related = relation.get(getRelationKey(source, target, /*isIntersectionConstituent*/ false, relation));
14305
14306
if (related !== undefined) {
14306
14307
return !!(related & RelationComparisonResult.Succeeded);
14307
14308
}
@@ -14353,7 +14354,6 @@ namespace ts {
14353
14354
let depth = 0;
14354
14355
let expandingFlags = ExpandingFlags.None;
14355
14356
let overflow = false;
14356
- let strictArityChecks = relation === subtypeRelation;
14357
14357
let overrideNextErrorInfo = 0; // How many `reportRelationError` calls should be skipped in the elaboration pyramid
14358
14358
let lastSkippedInfo: [Type, Type] | undefined;
14359
14359
let incompatibleStack: [DiagnosticMessage, (string | number)?, (string | number)?, (string | number)?, (string | number)?][] = [];
@@ -15142,7 +15142,7 @@ namespace ts {
15142
15142
if (overflow) {
15143
15143
return Ternary.False;
15144
15144
}
15145
- const id = getRelationKey(source, target, isIntersectionConstituent, strictArityChecks, relation);
15145
+ const id = getRelationKey(source, target, isIntersectionConstituent, relation);
15146
15146
const entry = relation.get(id);
15147
15147
if (entry !== undefined) {
15148
15148
if (reportErrors && entry & RelationComparisonResult.Failed && !(entry & RelationComparisonResult.Reported)) {
@@ -15438,7 +15438,7 @@ namespace ts {
15438
15438
}
15439
15439
else {
15440
15440
// An empty object type is related to any mapped type that includes a '?' modifier.
15441
- if (relation !== subtypeRelation && isPartialMappedType(target) && isEmptyObjectType(source)) {
15441
+ if (relation !== subtypeRelation && relation !== strictSubtypeRelation && isPartialMappedType(target) && isEmptyObjectType(source)) {
15442
15442
return Ternary.True;
15443
15443
}
15444
15444
if (isGenericMappedType(target)) {
@@ -15480,7 +15480,7 @@ namespace ts {
15480
15480
}
15481
15481
// Consider a fresh empty object literal type "closed" under the subtype relationship - this way `{} <- {[idx: string]: any} <- fresh({})`
15482
15482
// and not `{} <- fresh({}) <- {[idx: string]: any}`
15483
- else if (relation === subtypeRelation && isEmptyObjectType(target) && getObjectFlags(target) & ObjectFlags.FreshLiteral && !isEmptyObjectType(source)) {
15483
+ else if (( relation === subtypeRelation || relation === strictSubtypeRelation) && isEmptyObjectType(target) && getObjectFlags(target) & ObjectFlags.FreshLiteral && !isEmptyObjectType(source)) {
15484
15484
return Ternary.False;
15485
15485
}
15486
15486
// Even if relationship doesn't hold for unions, intersections, or generic type references,
@@ -15489,18 +15489,6 @@ namespace ts {
15489
15489
// to X. Failing both of those we want to check if the aggregation of A and B's members structurally
15490
15490
// relates to X. Thus, we include intersection types on the source side here.
15491
15491
if (source.flags & (TypeFlags.Object | TypeFlags.Intersection) && target.flags & TypeFlags.Object) {
15492
- // When performing strict arity checks for signatures (under the subtype relationship), if source has
15493
- // every property of target, and target is missing some properties from source, then we disable strict
15494
- // arity checks for the members. This decreases the chances of "ties" in union subtype reduction. For
15495
- // example, it enables us to consider { f(): void } a supertype of { f(x?: string): void, g(): void },
15496
- // which we need for backwards compatibility reasons (specifically, for Object and Number).
15497
- const saveStrictArityChecks = strictArityChecks;
15498
- if (strictArityChecks &&
15499
- !getUnmatchedProperty(source, target, /*requireOptionalProperties*/ true, /*matchDiscriminantProperties*/ false) &&
15500
- getUnmatchedProperty(target, source, /*requireOptionalProperties*/ true, /*matchDiscriminantProperties*/ false)) {
15501
- strictArityChecks = false;
15502
- }
15503
- // Report structural errors only if we haven't reported any errors yet
15504
15492
const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo.errorInfo && !sourceIsPrimitive;
15505
15493
result = propertiesRelatedTo(source, target, reportStructuralErrors, /*excludedProperties*/ undefined, isIntersectionConstituent);
15506
15494
if (result) {
@@ -15515,7 +15503,6 @@ namespace ts {
15515
15503
}
15516
15504
}
15517
15505
}
15518
- strictArityChecks = saveStrictArityChecks;
15519
15506
if (varianceCheckFailed && result) {
15520
15507
errorInfo = originalErrorInfo || errorInfo || saveErrorInfo.errorInfo; // Use variance error (there is no structural one) and return false
15521
15508
}
@@ -15837,7 +15824,7 @@ namespace ts {
15837
15824
if (relation === identityRelation) {
15838
15825
return propertiesIdenticalTo(source, target, excludedProperties);
15839
15826
}
15840
- const requireOptionalProperties = relation === subtypeRelation && !isObjectLiteralType(source) && !isEmptyArrayLiteralType(source) && !isTupleType(source);
15827
+ const requireOptionalProperties = ( relation === subtypeRelation || relation === strictSubtypeRelation) && !isObjectLiteralType(source) && !isEmptyArrayLiteralType(source) && !isTupleType(source);
15841
15828
const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false);
15842
15829
if (unmatchedProperty) {
15843
15830
if (reportErrors) {
@@ -16060,7 +16047,7 @@ namespace ts {
16060
16047
*/
16061
16048
function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean, incompatibleReporter: (source: Type, target: Type) => void): Ternary {
16062
16049
return compareSignaturesRelated(erase ? getErasedSignature(source) : source, erase ? getErasedSignature(target) : target,
16063
- strictArityChecks ? SignatureCheckMode.StrictArity : 0, reportErrors, reportError, incompatibleReporter, isRelatedTo, reportUnreliableMarkers);
16050
+ relation === strictSubtypeRelation ? SignatureCheckMode.StrictArity : 0, reportErrors, reportError, incompatibleReporter, isRelatedTo, reportUnreliableMarkers);
16064
16051
}
16065
16052
16066
16053
function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary {
@@ -16368,13 +16355,13 @@ namespace ts {
16368
16355
* To improve caching, the relation key for two generic types uses the target's id plus ids of the type parameters.
16369
16356
* For other cases, the types ids are used.
16370
16357
*/
16371
- function getRelationKey(source: Type, target: Type, isIntersectionConstituent: boolean, strictArityChecks: boolean, relation: Map<RelationComparisonResult>) {
16358
+ function getRelationKey(source: Type, target: Type, isIntersectionConstituent: boolean, relation: Map<RelationComparisonResult>) {
16372
16359
if (relation === identityRelation && source.id > target.id) {
16373
16360
const temp = source;
16374
16361
source = target;
16375
16362
target = temp;
16376
16363
}
16377
- const delimiter = isIntersectionConstituent ? strictArityChecks ? "|" : ";" : strictArityChecks ? "/ " : ",";
16364
+ const delimiter = isIntersectionConstituent ? "; " : ",";
16378
16365
if (isTypeReferenceWithGenericArguments(source) && isTypeReferenceWithGenericArguments(target)) {
16379
16366
const typeParameters: Type[] = [];
16380
16367
return getTypeReferenceId(<TypeReference>source, typeParameters) + delimiter + getTypeReferenceId(<TypeReference>target, typeParameters);
0 commit comments