Skip to content

Commit aa9230f

Browse files
Merge pull request #27020 from Kingwl/improve_accidentally_calling_type-assertion_expressions
improve Diagnostics for accidentally calling type-assertion expressions
2 parents e1daa47 + 2cf2bbd commit aa9230f

7 files changed

+179
-6
lines changed

src/compiler/checker.ts

+14-6
Original file line numberDiff line numberDiff line change
@@ -19672,7 +19672,14 @@ namespace ts {
1967219672
error(node, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType));
1967319673
}
1967419674
else {
19675-
invocationError(node, apparentType, SignatureKind.Call);
19675+
let relatedInformation: DiagnosticRelatedInformation | undefined;
19676+
if (node.arguments.length === 1 && isTypeAssertion(first(node.arguments))) {
19677+
const text = getSourceFileOfNode(node).text;
19678+
if (isLineBreak(text.charCodeAt(skipTrivia(text, node.expression.end, /* stopAfterLineBreak */ true) - 1))) {
19679+
relatedInformation = createDiagnosticForNode(node.expression, Diagnostics.It_is_highly_likely_that_you_are_missing_a_semicolon);
19680+
}
19681+
}
19682+
invocationError(node, apparentType, SignatureKind.Call, relatedInformation);
1967619683
}
1967719684
return resolveErrorCall(node);
1967819685
}
@@ -19842,11 +19849,12 @@ namespace ts {
1984219849
return true;
1984319850
}
1984419851

19845-
function invocationError(node: Node, apparentType: Type, kind: SignatureKind) {
19846-
invocationErrorRecovery(apparentType, kind, error(node, kind === SignatureKind.Call
19847-
? Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures
19848-
: Diagnostics.Cannot_use_new_with_an_expression_whose_type_lacks_a_call_or_construct_signature
19849-
, typeToString(apparentType)));
19852+
function invocationError(node: Node, apparentType: Type, kind: SignatureKind, relatedInformation?: DiagnosticRelatedInformation) {
19853+
const diagnostic = error(node, (kind === SignatureKind.Call ?
19854+
Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures :
19855+
Diagnostics.Cannot_use_new_with_an_expression_whose_type_lacks_a_call_or_construct_signature
19856+
), typeToString(apparentType));
19857+
invocationErrorRecovery(apparentType, kind, relatedInformation ? addRelatedInfo(diagnostic, relatedInformation) : diagnostic);
1985019858
}
1985119859

1985219860
function invocationErrorRecovery(apparentType: Type, kind: SignatureKind, diagnostic: Diagnostic) {

src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -2457,6 +2457,10 @@
24572457
"category": "Error",
24582458
"code": 2733
24592459
},
2460+
"It is highly likely that you are missing a semicolon.": {
2461+
"category": "Error",
2462+
"code": 2734
2463+
},
24602464

24612465
"Import declaration '{0}' is using private name '{1}'.": {
24622466
"category": "Error",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
tests/cases/compiler/betterErrorForAccidentallyCallingTypeAssertionExpressions.ts(3,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
2+
tests/cases/compiler/betterErrorForAccidentallyCallingTypeAssertionExpressions.ts(5,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
3+
tests/cases/compiler/betterErrorForAccidentallyCallingTypeAssertionExpressions.ts(7,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
4+
tests/cases/compiler/betterErrorForAccidentallyCallingTypeAssertionExpressions.ts(10,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
5+
tests/cases/compiler/betterErrorForAccidentallyCallingTypeAssertionExpressions.ts(13,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
6+
7+
8+
==== tests/cases/compiler/betterErrorForAccidentallyCallingTypeAssertionExpressions.ts (5 errors) ====
9+
declare function foo(): string;
10+
11+
foo()(1 as number).toString();
12+
~~~~~~~~~~~~~~~~~~
13+
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
14+
15+
foo() (1 as number).toString();
16+
~~~~~~~~~~~~~~~~~~~~~
17+
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
18+
19+
foo()
20+
~~~~~
21+
(1 as number).toString();
22+
~~~~~~~~~~~~~
23+
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
24+
!!! related TS2734 tests/cases/compiler/betterErrorForAccidentallyCallingTypeAssertionExpressions.ts:7:1: It is highly likely that you are missing a semicolon.
25+
26+
foo()
27+
~~~~~~~~
28+
(1 as number).toString();
29+
~~~~~~~~~~~~~~~~~
30+
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
31+
!!! related TS2734 tests/cases/compiler/betterErrorForAccidentallyCallingTypeAssertionExpressions.ts:10:1: It is highly likely that you are missing a semicolon.
32+
33+
foo()
34+
~~~~~~~~
35+
(<number>1).toString();
36+
~~~~~~~~~~~~~~~
37+
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
38+
!!! related TS2734 tests/cases/compiler/betterErrorForAccidentallyCallingTypeAssertionExpressions.ts:13:1: It is highly likely that you are missing a semicolon.
39+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//// [betterErrorForAccidentallyCallingTypeAssertionExpressions.ts]
2+
declare function foo(): string;
3+
4+
foo()(1 as number).toString();
5+
6+
foo() (1 as number).toString();
7+
8+
foo()
9+
(1 as number).toString();
10+
11+
foo()
12+
(1 as number).toString();
13+
14+
foo()
15+
(<number>1).toString();
16+
17+
18+
//// [betterErrorForAccidentallyCallingTypeAssertionExpressions.js]
19+
foo()(1).toString();
20+
foo()(1).toString();
21+
foo()(1).toString();
22+
foo()(1).toString();
23+
foo()(1).toString();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
=== tests/cases/compiler/betterErrorForAccidentallyCallingTypeAssertionExpressions.ts ===
2+
declare function foo(): string;
3+
>foo : Symbol(foo, Decl(betterErrorForAccidentallyCallingTypeAssertionExpressions.ts, 0, 0))
4+
5+
foo()(1 as number).toString();
6+
>foo : Symbol(foo, Decl(betterErrorForAccidentallyCallingTypeAssertionExpressions.ts, 0, 0))
7+
8+
foo() (1 as number).toString();
9+
>foo : Symbol(foo, Decl(betterErrorForAccidentallyCallingTypeAssertionExpressions.ts, 0, 0))
10+
11+
foo()
12+
>foo : Symbol(foo, Decl(betterErrorForAccidentallyCallingTypeAssertionExpressions.ts, 0, 0))
13+
14+
(1 as number).toString();
15+
16+
foo()
17+
>foo : Symbol(foo, Decl(betterErrorForAccidentallyCallingTypeAssertionExpressions.ts, 0, 0))
18+
19+
(1 as number).toString();
20+
21+
foo()
22+
>foo : Symbol(foo, Decl(betterErrorForAccidentallyCallingTypeAssertionExpressions.ts, 0, 0))
23+
24+
(<number>1).toString();
25+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
=== tests/cases/compiler/betterErrorForAccidentallyCallingTypeAssertionExpressions.ts ===
2+
declare function foo(): string;
3+
>foo : () => string
4+
5+
foo()(1 as number).toString();
6+
>foo()(1 as number).toString() : any
7+
>foo()(1 as number).toString : any
8+
>foo()(1 as number) : any
9+
>foo() : string
10+
>foo : () => string
11+
>1 as number : number
12+
>1 : 1
13+
>toString : any
14+
15+
foo() (1 as number).toString();
16+
>foo() (1 as number).toString() : any
17+
>foo() (1 as number).toString : any
18+
>foo() (1 as number) : any
19+
>foo() : string
20+
>foo : () => string
21+
>1 as number : number
22+
>1 : 1
23+
>toString : any
24+
25+
foo()
26+
>foo()(1 as number).toString() : any
27+
>foo()(1 as number).toString : any
28+
>foo()(1 as number) : any
29+
>foo() : string
30+
>foo : () => string
31+
32+
(1 as number).toString();
33+
>1 as number : number
34+
>1 : 1
35+
>toString : any
36+
37+
foo()
38+
>foo() (1 as number).toString() : any
39+
>foo() (1 as number).toString : any
40+
>foo() (1 as number) : any
41+
>foo() : string
42+
>foo : () => string
43+
44+
(1 as number).toString();
45+
>1 as number : number
46+
>1 : 1
47+
>toString : any
48+
49+
foo()
50+
>foo() (<number>1).toString() : any
51+
>foo() (<number>1).toString : any
52+
>foo() (<number>1) : any
53+
>foo() : string
54+
>foo : () => string
55+
56+
(<number>1).toString();
57+
><number>1 : number
58+
>1 : 1
59+
>toString : any
60+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
declare function foo(): string;
2+
3+
foo()(1 as number).toString();
4+
5+
foo() (1 as number).toString();
6+
7+
foo()
8+
(1 as number).toString();
9+
10+
foo()
11+
(1 as number).toString();
12+
13+
foo()
14+
(<number>1).toString();

0 commit comments

Comments
 (0)