@@ -609,6 +609,8 @@ namespace ts {
609
609
const assignableRelation = createMap<RelationComparisonResult>();
610
610
const definitelyAssignableRelation = createMap<RelationComparisonResult>();
611
611
const comparableRelation = createMap<RelationComparisonResult>();
612
+ // Same as comparableRelation except we do check for weak types.
613
+ const narrowableRelation = createMap<RelationComparisonResult>();
612
614
const identityRelation = createMap<RelationComparisonResult>();
613
615
const enumRelation = createMap<RelationComparisonResult>();
614
616
@@ -10906,7 +10908,7 @@ namespace ts {
10906
10908
if (s & TypeFlags.Null && (!strictNullChecks || t & TypeFlags.Null)) return true;
10907
10909
if (s & TypeFlags.Object && t & TypeFlags.NonPrimitive) return true;
10908
10910
if (s & TypeFlags.UniqueESSymbol || t & TypeFlags.UniqueESSymbol) return false;
10909
- if (relation === assignableRelation || relation === definitelyAssignableRelation || relation === comparableRelation) {
10911
+ if (relation === assignableRelation || relation === definitelyAssignableRelation || relation === comparableRelation || relation === narrowableRelation ) {
10910
10912
if (s & TypeFlags.Any) return true;
10911
10913
// Type number or any numeric literal type is assignable to any numeric enum type or any
10912
10914
// numeric enum literal type. This rule exists for backwards compatibility reasons because
@@ -10925,7 +10927,7 @@ namespace ts {
10925
10927
target = (<LiteralType>target).regularType;
10926
10928
}
10927
10929
if (source === target ||
10928
- relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) ||
10930
+ ( relation === comparableRelation || relation === narrowableRelation) && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) ||
10929
10931
relation !== identityRelation && isSimpleTypeRelatedTo(source, target, relation)) {
10930
10932
return true;
10931
10933
}
@@ -11025,7 +11027,7 @@ namespace ts {
11025
11027
}
11026
11028
11027
11029
if (!message) {
11028
- if (relation === comparableRelation) {
11030
+ if (relation === comparableRelation || relation === narrowableRelation ) {
11029
11031
message = Diagnostics.Type_0_is_not_comparable_to_type_1;
11030
11032
}
11031
11033
else if (sourceType === targetType) {
@@ -11120,7 +11122,7 @@ namespace ts {
11120
11122
return isIdenticalTo(source, target);
11121
11123
}
11122
11124
11123
- if (relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) ||
11125
+ if (( relation === comparableRelation || relation === narrowableRelation) && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) ||
11124
11126
isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True;
11125
11127
11126
11128
if (isObjectLiteralType(source) && source.flags & TypeFlags.FreshLiteral) {
@@ -11171,7 +11173,7 @@ namespace ts {
11171
11173
// we need to deconstruct unions before intersections (because unions are always at the top),
11172
11174
// and we need to handle "each" relations before "some" relations for the same kind of type.
11173
11175
if (source.flags & TypeFlags.Union) {
11174
- result = relation === comparableRelation ?
11176
+ result = ( relation === comparableRelation || relation === narrowableRelation) ?
11175
11177
someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive)) :
11176
11178
eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive));
11177
11179
}
@@ -11295,7 +11297,7 @@ namespace ts {
11295
11297
}
11296
11298
if (maybeTypeOfKind(target, TypeFlags.Object) && !(getObjectFlags(target) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) {
11297
11299
const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes);
11298
- if ((relation === assignableRelation || relation === definitelyAssignableRelation || relation === comparableRelation) &&
11300
+ if ((relation === assignableRelation || relation === definitelyAssignableRelation || relation === comparableRelation || relation === narrowableRelation ) &&
11299
11301
(isTypeSubsetOf(globalObjectType, target) || (!isComparingJsxAttributes && isEmptyObjectType(target)))) {
11300
11302
return false;
11301
11303
}
@@ -11813,7 +11815,7 @@ namespace ts {
11813
11815
// related to Y, where X' is an instantiation of X in which P is replaced with Q. Notice
11814
11816
// that S and T are contra-variant whereas X and Y are co-variant.
11815
11817
function mappedTypeRelatedTo(source: MappedType, target: MappedType, reportErrors: boolean): Ternary {
11816
- const modifiersRelated = relation === comparableRelation || (relation === identityRelation ? getMappedTypeModifiers(source) === getMappedTypeModifiers(target) :
11818
+ const modifiersRelated = relation === comparableRelation || relation === narrowableRelation || (relation === identityRelation ? getMappedTypeModifiers(source) === getMappedTypeModifiers(target) :
11817
11819
getCombinedMappedTypeOptionality(source) <= getCombinedMappedTypeOptionality(target));
11818
11820
if (modifiersRelated) {
11819
11821
let result: Ternary;
@@ -11935,7 +11937,7 @@ namespace ts {
11935
11937
}
11936
11938
result &= related;
11937
11939
// When checking for comparability, be more lenient with optional properties.
11938
- if (relation !== comparableRelation && sourceProp.flags & SymbolFlags.Optional && !(targetProp.flags & SymbolFlags.Optional)) {
11940
+ if (relation !== comparableRelation && relation !== narrowableRelation && sourceProp.flags & SymbolFlags.Optional && !(targetProp.flags & SymbolFlags.Optional)) {
11939
11941
// TypeScript 1.0 spec (April 2014): 3.8.3
11940
11942
// S is a subtype of a type T, and T is a supertype of S if ...
11941
11943
// S' and T are object types and, for each member M in T..
@@ -12055,7 +12057,7 @@ namespace ts {
12055
12057
// in the context of the target signature before checking the relationship. Ideally we'd do
12056
12058
// this regardless of the number of signatures, but the potential costs are prohibitive due
12057
12059
// to the quadratic nature of the logic below.
12058
- const eraseGenerics = relation === comparableRelation || !!compilerOptions.noStrictGenericChecks;
12060
+ const eraseGenerics = relation === comparableRelation || relation === narrowableRelation || !!compilerOptions.noStrictGenericChecks;
12059
12061
result = signatureRelatedTo(sourceSignatures[0], targetSignatures[0], eraseGenerics, reportErrors);
12060
12062
}
12061
12063
else {
@@ -13878,7 +13880,9 @@ namespace ts {
13878
13880
if (assignedType.flags & TypeFlags.Never) {
13879
13881
return assignedType;
13880
13882
}
13881
- const reducedType = filterType(declaredType, t => isTypeComparableTo(assignedType, t));
13883
+ const reducedType = filterType(declaredType, t => isTypeRelatedTo(assignedType, t, narrowableRelation));
13884
+ // If the assignment was originally valid, it should still be valid with the reduced target type.
13885
+ Debug.assert(!isTypeAssignableTo(assignedType, declaredType) || isTypeAssignableTo(assignedType, reducedType));
13882
13886
if (!(reducedType.flags & TypeFlags.Never)) {
13883
13887
return reducedType;
13884
13888
}
0 commit comments