Skip to content

Commit 4dbae54

Browse files
committed
Merge pull request #5639 from Microsoft/typecheckStatementsInCaseClause
always check statements in case clause
2 parents b3c4733 + ebd1b87 commit 4dbae54

File tree

5 files changed

+106
-6
lines changed

5 files changed

+106
-6
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12886,13 +12886,13 @@ namespace ts {
1288612886
// In a 'switch' statement, each 'case' expression must be of a type that is assignable to or from the type of the 'switch' expression.
1288712887
const caseType = checkExpression(caseClause.expression);
1288812888

12889-
// Permit 'number[] | "foo"' to be asserted to 'string'.
12890-
if (expressionTypeIsStringLike && someConstituentTypeHasKind(caseType, TypeFlags.StringLike)) {
12891-
return;
12892-
}
12889+
const expressionTypeIsAssignableToCaseType =
12890+
// Permit 'number[] | "foo"' to be asserted to 'string'.
12891+
(expressionTypeIsStringLike && someConstituentTypeHasKind(caseType, TypeFlags.StringLike)) ||
12892+
isTypeAssignableTo(expressionType, caseType);
1289312893

12894-
if (!isTypeAssignableTo(expressionType, caseType)) {
12895-
// check 'expressionType isAssignableTo caseType' failed, try the reversed check and report errors if it fails
12894+
if (!expressionTypeIsAssignableToCaseType) {
12895+
// 'expressionType is not assignable to caseType', try the reversed check and report errors if it fails
1289612896
checkTypeAssignableTo(caseType, expressionType, caseClause.expression, /*headMessage*/ undefined);
1289712897
}
1289812898
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//// [checkSwitchStatementIfCaseTypeIsString.ts]
2+
declare function use(a: any): void;
3+
4+
class A {
5+
doIt(x: Array<string>): void {
6+
x.forEach((v) => {
7+
switch(v) {
8+
case "test": use(this);
9+
}
10+
});
11+
}
12+
}
13+
14+
//// [checkSwitchStatementIfCaseTypeIsString.js]
15+
var A = (function () {
16+
function A() {
17+
}
18+
A.prototype.doIt = function (x) {
19+
var _this = this;
20+
x.forEach(function (v) {
21+
switch (v) {
22+
case "test": use(_this);
23+
}
24+
});
25+
};
26+
return A;
27+
})();
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
=== tests/cases/compiler/checkSwitchStatementIfCaseTypeIsString.ts ===
2+
declare function use(a: any): void;
3+
>use : Symbol(use, Decl(checkSwitchStatementIfCaseTypeIsString.ts, 0, 0))
4+
>a : Symbol(a, Decl(checkSwitchStatementIfCaseTypeIsString.ts, 0, 21))
5+
6+
class A {
7+
>A : Symbol(A, Decl(checkSwitchStatementIfCaseTypeIsString.ts, 0, 35))
8+
9+
doIt(x: Array<string>): void {
10+
>doIt : Symbol(doIt, Decl(checkSwitchStatementIfCaseTypeIsString.ts, 2, 9))
11+
>x : Symbol(x, Decl(checkSwitchStatementIfCaseTypeIsString.ts, 3, 9))
12+
>Array : Symbol(Array, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
13+
14+
x.forEach((v) => {
15+
>x.forEach : Symbol(Array.forEach, Decl(lib.d.ts, --, --))
16+
>x : Symbol(x, Decl(checkSwitchStatementIfCaseTypeIsString.ts, 3, 9))
17+
>forEach : Symbol(Array.forEach, Decl(lib.d.ts, --, --))
18+
>v : Symbol(v, Decl(checkSwitchStatementIfCaseTypeIsString.ts, 4, 19))
19+
20+
switch(v) {
21+
>v : Symbol(v, Decl(checkSwitchStatementIfCaseTypeIsString.ts, 4, 19))
22+
23+
case "test": use(this);
24+
>use : Symbol(use, Decl(checkSwitchStatementIfCaseTypeIsString.ts, 0, 0))
25+
>this : Symbol(A, Decl(checkSwitchStatementIfCaseTypeIsString.ts, 0, 35))
26+
}
27+
});
28+
}
29+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
=== tests/cases/compiler/checkSwitchStatementIfCaseTypeIsString.ts ===
2+
declare function use(a: any): void;
3+
>use : (a: any) => void
4+
>a : any
5+
6+
class A {
7+
>A : A
8+
9+
doIt(x: Array<string>): void {
10+
>doIt : (x: string[]) => void
11+
>x : string[]
12+
>Array : T[]
13+
14+
x.forEach((v) => {
15+
>x.forEach((v) => { switch(v) { case "test": use(this); } }) : void
16+
>x.forEach : (callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any) => void
17+
>x : string[]
18+
>forEach : (callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any) => void
19+
>(v) => { switch(v) { case "test": use(this); } } : (v: string) => void
20+
>v : string
21+
22+
switch(v) {
23+
>v : string
24+
25+
case "test": use(this);
26+
>"test" : string
27+
>use(this) : void
28+
>use : (a: any) => void
29+
>this : this
30+
}
31+
});
32+
}
33+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
declare function use(a: any): void;
2+
3+
class A {
4+
doIt(x: Array<string>): void {
5+
x.forEach((v) => {
6+
switch(v) {
7+
case "test": use(this);
8+
}
9+
});
10+
}
11+
}

0 commit comments

Comments
 (0)