@@ -9400,7 +9400,12 @@ namespace ts {
9400
9400
let targetType = getTypeFromTypeNode(node.type);
9401
9401
if (produceDiagnostics && targetType !== unknownType) {
9402
9402
let widenedType = getWidenedType(exprType);
9403
- if (!(isTypeAssignableTo(targetType, widenedType))) {
9403
+
9404
+ // Permit 'number[] | "foo"' to be asserted to 'string'.
9405
+ const bothAreStringLike =
9406
+ someConstituentTypeHasKind(targetType, TypeFlags.StringLike) &&
9407
+ someConstituentTypeHasKind(widenedType, TypeFlags.StringLike);
9408
+ if (!bothAreStringLike && !(isTypeAssignableTo(targetType, widenedType))) {
9404
9409
checkTypeAssignableTo(exprType, targetType, node, Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other);
9405
9410
}
9406
9411
}
@@ -10244,6 +10249,10 @@ namespace ts {
10244
10249
case SyntaxKind.ExclamationEqualsToken:
10245
10250
case SyntaxKind.EqualsEqualsEqualsToken:
10246
10251
case SyntaxKind.ExclamationEqualsEqualsToken:
10252
+ // Permit 'number[] | "foo"' to be asserted to 'string'.
10253
+ if (someConstituentTypeHasKind(leftType, TypeFlags.StringLike) && someConstituentTypeHasKind(rightType, TypeFlags.StringLike)) {
10254
+ return booleanType;
10255
+ }
10247
10256
if (!isTypeAssignableTo(leftType, rightType) && !isTypeAssignableTo(rightType, leftType)) {
10248
10257
reportOperatorError();
10249
10258
}
@@ -12703,6 +12712,7 @@ namespace ts {
12703
12712
let hasDuplicateDefaultClause = false;
12704
12713
12705
12714
let expressionType = checkExpression(node.expression);
12715
+ const expressionTypeIsStringLike = someConstituentTypeHasKind(expressionType, TypeFlags.StringLike);
12706
12716
forEach(node.caseBlock.clauses, clause => {
12707
12717
// Grammar check for duplicate default clauses, skip if we already report duplicate default clause
12708
12718
if (clause.kind === SyntaxKind.DefaultClause && !hasDuplicateDefaultClause) {
@@ -12723,6 +12733,12 @@ namespace ts {
12723
12733
// TypeScript 1.0 spec (April 2014):5.9
12724
12734
// In a 'switch' statement, each 'case' expression must be of a type that is assignable to or from the type of the 'switch' expression.
12725
12735
let caseType = checkExpression(caseClause.expression);
12736
+
12737
+ // Permit 'number[] | "foo"' to be asserted to 'string'.
12738
+ if (expressionTypeIsStringLike && someConstituentTypeHasKind(caseType, TypeFlags.StringLike)) {
12739
+ return;
12740
+ }
12741
+
12726
12742
if (!isTypeAssignableTo(expressionType, caseType)) {
12727
12743
// check 'expressionType isAssignableTo caseType' failed, try the reversed check and report errors if it fails
12728
12744
checkTypeAssignableTo(caseType, expressionType, caseClause.expression, /*headMessage*/ undefined);
0 commit comments