@@ -873,6 +873,7 @@ namespace ts {
873873 const subtypeRelation = createMap<RelationComparisonResult>();
874874 const assignableRelation = createMap<RelationComparisonResult>();
875875 const comparableRelation = createMap<RelationComparisonResult>();
876+ const castableRelation = createMap<RelationComparisonResult>();
876877 const identityRelation = createMap<RelationComparisonResult>();
877878 const enumRelation = createMap<RelationComparisonResult>();
878879
@@ -13394,6 +13395,18 @@ namespace ts {
1339413395 hasBaseType(source, getTargetType(target));
1339513396 }
1339613397
13398+ /**
13399+ * This is *not* a bi-directional relationship.
13400+ * If one needs to check both directions for castability, use a second call to this function or 'checkTypeCastableTo'.
13401+ *
13402+ * A type S is comparable to a type T if some (but not necessarily all) of the possible values of S are also possible values of T.
13403+ * It is used to check following cases:
13404+ * - the type of an expression in a type assertion with the type being asserted.
13405+ */
13406+ function isTypeCastableTo(source: Type, target: Type): boolean {
13407+ return isTypeRelatedTo(source, target, castableRelation);
13408+ }
13409+
1339713410 /**
1339813411 * This is *not* a bi-directional relationship.
1339913412 * If one needs to check both directions for comparability, use a second call to this function or 'checkTypeComparableTo'.
@@ -13402,7 +13415,6 @@ namespace ts {
1340213415 * It is used to check following cases:
1340313416 * - the types of the left and right sides of equality/inequality operators (`===`, `!==`, `==`, `!=`).
1340413417 * - the types of `case` clause expressions and their respective `switch` expressions.
13405- * - the type of an expression in a type assertion with the type being asserted.
1340613418 */
1340713419 function isTypeComparableTo(source: Type, target: Type): boolean {
1340813420 return isTypeRelatedTo(source, target, comparableRelation);
@@ -13835,6 +13847,14 @@ namespace ts {
1383513847 return elaborateElementwise(generateObjectLiteralElements(node), source, target, relation, containingMessageChain, errorOutputContainer);
1383613848 }
1383713849
13850+ /**
13851+ * This is *not* a bi-directional relationship.
13852+ * If one needs to check both directions for comparability, use a second call to this function or 'isTypeComparableTo'.
13853+ */
13854+ function checkTypeCastableTo(source: Type, target: Type, errorNode: Node, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined): boolean {
13855+ return checkTypeRelatedTo(source, target, castableRelation, errorNode, headMessage, containingMessageChain);
13856+ }
13857+
1383813858 /**
1383913859 * This is *not* a bi-directional relationship.
1384013860 * If one needs to check both directions for comparability, use a second call to this function or 'isTypeComparableTo'.
@@ -14133,7 +14153,7 @@ namespace ts {
1413314153 if (s & TypeFlags.Undefined && (!strictNullChecks || t & (TypeFlags.Undefined | TypeFlags.Void))) return true;
1413414154 if (s & TypeFlags.Null && (!strictNullChecks || t & TypeFlags.Null)) return true;
1413514155 if (s & TypeFlags.Object && t & TypeFlags.NonPrimitive) return true;
14136- if (relation === assignableRelation || relation === comparableRelation) {
14156+ if (relation === assignableRelation || relation === comparableRelation || relation === castableRelation ) {
1413714157 if (s & TypeFlags.Any) return true;
1413814158 // Type number or any numeric literal type is assignable to any numeric enum type or any
1413914159 // numeric enum literal type. This rule exists for backwards compatibility reasons because
@@ -14152,7 +14172,7 @@ namespace ts {
1415214172 target = (<FreshableType>target).regularType;
1415314173 }
1415414174 if (source === target ||
14155- relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) ||
14175+ ( relation === comparableRelation || relation === castableRelation) && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) ||
1415614176 relation !== identityRelation && isSimpleTypeRelatedTo(source, target, relation)) {
1415714177 return true;
1415814178 }
@@ -14176,7 +14196,7 @@ namespace ts {
1417614196 * Checks if 'source' is related to 'target' (e.g.: is a assignable to).
1417714197 * @param source The left-hand-side of the relation.
1417814198 * @param target The right-hand-side of the relation.
14179- * @param relation The relation considered. One of 'identityRelation', 'subtypeRelation', 'assignableRelation', or 'comparableRelation '.
14199+ * @param relation The relation considered. One of 'identityRelation', 'subtypeRelation', 'assignableRelation', 'comparableRelation', or 'castableRelation '.
1418014200 * Used as both to determine which checks are performed and as a cache of previously computed results.
1418114201 * @param errorNode The suggested node upon which all errors will be reported, if defined. This may or may not be the actual node used.
1418214202 * @param headMessage If the error chain should be prepended by a head message, then headMessage will be used.
@@ -14410,7 +14430,7 @@ namespace ts {
1441014430 }
1441114431
1441214432 if (!message) {
14413- if (relation === comparableRelation) {
14433+ if (relation === comparableRelation || relation === castableRelation ) {
1441414434 message = Diagnostics.Type_0_is_not_comparable_to_type_1;
1441514435 }
1441614436 else if (sourceType === targetType) {
@@ -14520,7 +14540,7 @@ namespace ts {
1452014540 return isIdenticalTo(source, target);
1452114541 }
1452214542
14523- if (relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) ||
14543+ if (( relation === comparableRelation || relation === castableRelation) && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) ||
1452414544 isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True;
1452514545
1452614546 const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes);
@@ -14534,8 +14554,7 @@ namespace ts {
1453414554 return Ternary.False;
1453514555 }
1453614556 }
14537-
14538- const isPerformingCommonPropertyChecks = relation !== comparableRelation && !isApparentIntersectionConstituent &&
14557+ const isPerformingCommonPropertyChecks = relation !== castableRelation && !isApparentIntersectionConstituent &&
1453914558 source.flags & (TypeFlags.Primitive | TypeFlags.Object | TypeFlags.Intersection) && source !== globalObjectType &&
1454014559 target.flags & (TypeFlags.Object | TypeFlags.Intersection) && isWeakType(target) &&
1454114560 (getPropertiesOfType(source).length > 0 || typeHasCallOrConstructSignatures(source));
@@ -14562,7 +14581,7 @@ namespace ts {
1456214581 // we need to deconstruct unions before intersections (because unions are always at the top),
1456314582 // and we need to handle "each" relations before "some" relations for the same kind of type.
1456414583 if (source.flags & TypeFlags.Union) {
14565- result = relation === comparableRelation ?
14584+ result = relation === comparableRelation || relation === castableRelation ?
1456614585 someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), isIntersectionConstituent) :
1456714586 eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive));
1456814587 }
@@ -14694,7 +14713,7 @@ namespace ts {
1469414713 }
1469514714 if (isExcessPropertyCheckTarget(target)) {
1469614715 const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes);
14697- if ((relation === assignableRelation || relation === comparableRelation) &&
14716+ if ((relation === assignableRelation || relation === comparableRelation || relation === castableRelation ) &&
1469814717 (isTypeSubsetOf(globalObjectType, target) || (!isComparingJsxAttributes && isEmptyObjectType(target)))) {
1469914718 return false;
1470014719 }
@@ -15435,7 +15454,7 @@ namespace ts {
1543515454 // related to Y, where X' is an instantiation of X in which P is replaced with Q. Notice
1543615455 // that S and T are contra-variant whereas X and Y are co-variant.
1543715456 function mappedTypeRelatedTo(source: MappedType, target: MappedType, reportErrors: boolean): Ternary {
15438- const modifiersRelated = relation === comparableRelation || (relation === identityRelation ? getMappedTypeModifiers(source) === getMappedTypeModifiers(target) :
15457+ const modifiersRelated = relation === comparableRelation || relation === castableRelation || (relation === identityRelation ? getMappedTypeModifiers(source) === getMappedTypeModifiers(target) :
1543915458 getCombinedMappedTypeOptionality(source) <= getCombinedMappedTypeOptionality(target));
1544015459 if (modifiersRelated) {
1544115460 let result: Ternary;
@@ -15651,7 +15670,7 @@ namespace ts {
1565115670 return Ternary.False;
1565215671 }
1565315672 // When checking for comparability, be more lenient with optional properties.
15654- if (relation !== comparableRelation && sourceProp.flags & SymbolFlags.Optional && !(targetProp.flags & SymbolFlags.Optional)) {
15673+ if (( relation !== comparableRelation && relation !== castableRelation) && sourceProp.flags & SymbolFlags.Optional && !(targetProp.flags & SymbolFlags.Optional)) {
1565515674 // TypeScript 1.0 spec (April 2014): 3.8.3
1565615675 // S is a subtype of a type T, and T is a supertype of S if ...
1565715676 // S' and T are object types and, for each member M in T..
@@ -15848,7 +15867,7 @@ namespace ts {
1584815867 // in the context of the target signature before checking the relationship. Ideally we'd do
1584915868 // this regardless of the number of signatures, but the potential costs are prohibitive due
1585015869 // to the quadratic nature of the logic below.
15851- const eraseGenerics = relation === comparableRelation || !!compilerOptions.noStrictGenericChecks;
15870+ const eraseGenerics = relation === comparableRelation || relation === castableRelation || !!compilerOptions.noStrictGenericChecks;
1585215871 result = signatureRelatedTo(sourceSignatures[0], targetSignatures[0], eraseGenerics, reportErrors, incompatibleReporter(sourceSignatures[0], targetSignatures[0]));
1585315872 }
1585415873 else {
@@ -25245,8 +25264,8 @@ namespace ts {
2524525264 const targetType = getTypeFromTypeNode(type);
2524625265 if (produceDiagnostics && targetType !== errorType) {
2524725266 const widenedType = getWidenedType(exprType);
25248- if (!isTypeComparableTo (targetType, widenedType)) {
25249- checkTypeComparableTo (exprType, targetType, errNode,
25267+ if (!isTypeCastableTo (targetType, widenedType)) {
25268+ checkTypeCastableTo (exprType, targetType, errNode,
2525025269 Diagnostics.Conversion_of_type_0_to_type_1_may_be_a_mistake_because_neither_type_sufficiently_overlaps_with_the_other_If_this_was_intentional_convert_the_expression_to_unknown_first);
2525125270 }
2525225271 }
0 commit comments