Skip to content

Commit 14d3c69

Browse files
committed
Disallow exprs of type void to be used in truthiness checks
1 parent 3ef067f commit 14d3c69

File tree

5 files changed

+47
-5
lines changed

5 files changed

+47
-5
lines changed

src/compiler/checker.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24512,7 +24512,7 @@ namespace ts {
2451224512
// Grammar checking
2451324513
checkGrammarStatementInAmbientContext(node);
2451424514

24515-
checkExpression(node.expression);
24515+
checkTruthinessExpression(node.expression);
2451624516
checkSourceElement(node.thenStatement);
2451724517

2451824518
if (node.thenStatement.kind === SyntaxKind.EmptyStatement) {
@@ -24527,17 +24527,25 @@ namespace ts {
2452724527
checkGrammarStatementInAmbientContext(node);
2452824528

2452924529
checkSourceElement(node.statement);
24530-
checkExpression(node.expression);
24530+
checkTruthinessExpression(node.expression);
2453124531
}
2453224532

2453324533
function checkWhileStatement(node: WhileStatement) {
2453424534
// Grammar checking
2453524535
checkGrammarStatementInAmbientContext(node);
2453624536

24537-
checkExpression(node.expression);
24537+
checkTruthinessExpression(node.expression);
2453824538
checkSourceElement(node.statement);
2453924539
}
2454024540

24541+
function checkTruthinessExpression(node: Expression) {
24542+
const type = checkExpression(node);
24543+
if (type === voidType) {
24544+
error(node, Diagnostics.An_expression_of_type_void_cannot_be_tested_for_truthiness);
24545+
}
24546+
return type;
24547+
}
24548+
2454124549
function checkForStatement(node: ForStatement) {
2454224550
// Grammar checking
2454324551
if (!checkGrammarStatementInAmbientContext(node)) {
@@ -24555,7 +24563,7 @@ namespace ts {
2455524563
}
2455624564
}
2455724565

24558-
if (node.condition) checkExpression(node.condition);
24566+
if (node.condition) checkTruthinessExpression(node.condition);
2455924567
if (node.incrementor) checkExpression(node.incrementor);
2456024568
checkSourceElement(node.statement);
2456124569
if (node.locals) {

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -987,6 +987,10 @@
987987
"category": "Error",
988988
"code": 1344
989989
},
990+
"An expression of type 'void' cannot be tested for truthiness": {
991+
"category": "Error",
992+
"code": 1345
993+
},
990994

991995
"Duplicate identifier '{0}'.": {
992996
"category": "Error",

src/server/scriptInfo.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,12 +459,15 @@ namespace ts.server {
459459
if (this.isDynamicOrHasMixedContent()) {
460460
this.textStorage.reload("");
461461
this.markContainingProjectsAsDirty();
462+
return true;
462463
}
463464
else {
464465
if (this.textStorage.reloadWithFileText(tempFileName)) {
465466
this.markContainingProjectsAsDirty();
467+
return true;
466468
}
467469
}
470+
return false;
468471
}
469472

470473
/*@internal*/

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8114,7 +8114,7 @@ declare namespace ts.server {
81148114
setOptions(formatSettings: FormatCodeSettings, preferences: UserPreferences | undefined): void;
81158115
getLatestVersion(): string;
81168116
saveTo(fileName: string): void;
8117-
reloadFromFile(tempFileName?: NormalizedPath): void;
8117+
reloadFromFile(tempFileName?: NormalizedPath): boolean;
81188118
editContent(start: number, end: number, newText: string): void;
81198119
markContainingProjectsAsDirty(): void;
81208120
isOrphan(): boolean;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
tests/cases/compiler/typePredicateInLoop.ts(17,11): error TS1345: An expression of type 'void' cannot be tested for truthiness
2+
3+
4+
==== tests/cases/compiler/typePredicateInLoop.ts (1 errors) ====
5+
// Repro from #12101
6+
7+
interface Type {
8+
type: number;
9+
}
10+
11+
interface TypeExt extends Type {
12+
arr: Type[];
13+
}
14+
15+
const guard = (arg: Type): arg is TypeExt => arg.type === 1;
16+
const otherFunc = (arg1: Type, arg2: TypeExt): void => {};
17+
18+
export function y(arg: Type): void {
19+
if (guard(arg)) {
20+
for (const ITEM of arg.arr) {
21+
if (otherFunc(ITEM, arg)) {
22+
~~~~~~~~~~~~~~~~~~~~
23+
!!! error TS1345: An expression of type 'void' cannot be tested for truthiness
24+
}
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)