Skip to content

Commit 768318b

Browse files
Improved error message for calling/constructing types
1 parent 2af8ac7 commit 768318b

File tree

48 files changed

+491
-148
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+491
-148
lines changed

src/compiler/checker.ts

Lines changed: 77 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22015,11 +22015,83 @@ namespace ts {
2201522015
return true;
2201622016
}
2201722017

22018+
function invocationErrorDetails(apparentType: Type, kind: SignatureKind): DiagnosticMessageChain {
22019+
let errorInfo: DiagnosticMessageChain | undefined;
22020+
const isCall = kind === SignatureKind.Call;
22021+
if (apparentType.flags & TypeFlags.Union) {
22022+
const types = (apparentType as UnionType).types;
22023+
let hasSignatures = false;
22024+
for (const constituent of types) {
22025+
const signatures = getSignaturesOfType(constituent, kind);
22026+
if (signatures.length !== 0) {
22027+
hasSignatures = true;
22028+
if (errorInfo) {
22029+
// Bail early if we already have an error, no chance of "No constituent of type is callable"
22030+
break;
22031+
}
22032+
}
22033+
else {
22034+
// Error on the first non callable constituent only
22035+
if (!errorInfo) {
22036+
errorInfo = chainDiagnosticMessages(
22037+
errorInfo,
22038+
isCall ?
22039+
Diagnostics.Type_0_has_no_call_signatures :
22040+
Diagnostics.Type_0_has_no_construct_signatures,
22041+
typeToString(constituent)
22042+
);
22043+
errorInfo = chainDiagnosticMessages(
22044+
errorInfo,
22045+
isCall ?
22046+
Diagnostics.Not_all_constituents_of_type_0_are_callable :
22047+
Diagnostics.Not_all_constituents_of_type_0_are_constructable,
22048+
typeToString(apparentType)
22049+
);
22050+
}
22051+
if (hasSignatures) {
22052+
// Bail early if we already found a siganture, no chance of "No constituent of type is callable"
22053+
break;
22054+
}
22055+
}
22056+
}
22057+
if (!hasSignatures) {
22058+
errorInfo = chainDiagnosticMessages(
22059+
/* detials */ undefined,
22060+
isCall ?
22061+
Diagnostics.No_constituent_of_type_0_is_callable :
22062+
Diagnostics.No_constituent_of_type_0_is_constructable,
22063+
typeToString(apparentType)
22064+
);
22065+
}
22066+
if (!errorInfo) {
22067+
errorInfo = chainDiagnosticMessages(
22068+
errorInfo,
22069+
isCall ?
22070+
Diagnostics.Each_member_of_the_union_type_0_has_signatures_but_none_of_those_signatures_are_compatible_with_each_other :
22071+
Diagnostics.Each_member_of_the_union_type_0_has_construct_signatures_but_none_of_those_signatures_are_compatible_with_each_other,
22072+
typeToString(apparentType)
22073+
);
22074+
}
22075+
}
22076+
else {
22077+
errorInfo = chainDiagnosticMessages(
22078+
errorInfo,
22079+
isCall ?
22080+
Diagnostics.Type_0_has_no_call_signatures :
22081+
Diagnostics.Type_0_has_no_construct_signatures,
22082+
typeToString(apparentType)
22083+
);
22084+
}
22085+
return chainDiagnosticMessages(
22086+
errorInfo,
22087+
isCall ?
22088+
Diagnostics.This_expression_is_not_callable :
22089+
Diagnostics.This_expression_is_not_constructable
22090+
);
22091+
}
2201822092
function invocationError(node: Node, apparentType: Type, kind: SignatureKind, relatedInformation?: DiagnosticRelatedInformation) {
22019-
const diagnostic = error(node, (kind === SignatureKind.Call ?
22020-
Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures :
22021-
Diagnostics.Cannot_use_new_with_an_expression_whose_type_lacks_a_call_or_construct_signature
22022-
), typeToString(apparentType));
22093+
const diagnostic: Diagnostic = createDiagnosticForNodeFromMessageChain(node, invocationErrorDetails(apparentType, kind));
22094+
diagnostics.add(diagnostic);
2202322095
invocationErrorRecovery(apparentType, kind, relatedInformation ? addRelatedInfo(diagnostic, relatedInformation) : diagnostic);
2202422096
}
2202522097

@@ -22113,7 +22185,7 @@ namespace ts {
2211322185

2211422186
const headMessage = getDiagnosticHeadMessageForDecoratorResolution(node);
2211522187
if (!callSignatures.length) {
22116-
let errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, typeToString(apparentType));
22188+
let errorInfo = invocationErrorDetails(apparentType, SignatureKind.Call);
2211722189
errorInfo = chainDiagnosticMessages(errorInfo, headMessage);
2211822190
const diag = createDiagnosticForNodeFromMessageChain(node, errorInfo);
2211922191
diagnostics.add(diag);

src/compiler/diagnosticMessages.json

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,15 +1236,15 @@
12361236
"category": "Error",
12371237
"code": 2348
12381238
},
1239-
"Cannot invoke an expression whose type lacks a call signature. Type '{0}' has no compatible call signatures.": {
1239+
"This expression is not callable.": {
12401240
"category": "Error",
12411241
"code": 2349
12421242
},
12431243
"Only a void function can be called with the 'new' keyword.": {
12441244
"category": "Error",
12451245
"code": 2350
12461246
},
1247-
"Cannot use 'new' with an expression whose type lacks a call or construct signature.": {
1247+
"This expression is not constructable.": {
12481248
"category": "Error",
12491249
"code": 2351
12501250
},
@@ -2621,6 +2621,38 @@
26212621
"category": "Error",
26222622
"code": 2754
26232623
},
2624+
"No constituent of type '{0}' is callable.": {
2625+
"category": "Error",
2626+
"code": 2755
2627+
},
2628+
"Not all constituents of type '{0}' are callable.": {
2629+
"category": "Error",
2630+
"code": 2756
2631+
},
2632+
"Type '{0}' has no call signatures.": {
2633+
"category": "Error",
2634+
"code": 2757
2635+
},
2636+
"Each member of the union type '{0}' has signatures, but none of those signatures are compatible with each other.": {
2637+
"category": "Error",
2638+
"code": 2758
2639+
},
2640+
"No constituent of type '{0}' is constructable.": {
2641+
"category": "Error",
2642+
"code": 2759
2643+
},
2644+
"Not all constituents of type '{0}' are constructable.": {
2645+
"category": "Error",
2646+
"code": 2760
2647+
},
2648+
"Type '{0}' has no construct signatures.": {
2649+
"category": "Error",
2650+
"code": 2761
2651+
},
2652+
"Each member of the union type '{0}' has construct signatures, but none of those signatures are compatible with each other.": {
2653+
"category": "Error",
2654+
"code": 2762
2655+
},
26242656

26252657
"Import declaration '{0}' is using private name '{1}'.": {
26262658
"category": "Error",

src/services/codefixes/fixInvalidImportSyntax.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ namespace ts.codefix {
3131

3232
registerCodeFix({
3333
errorCodes: [
34-
Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures.code,
35-
Diagnostics.Cannot_use_new_with_an_expression_whose_type_lacks_a_call_or_construct_signature.code,
34+
Diagnostics.This_expression_is_not_callable.code,
35+
Diagnostics.This_expression_is_not_constructable.code,
3636
],
3737
getCodeActions: getActionsForUsageOfInvalidImport
3838
});
3939

4040
function getActionsForUsageOfInvalidImport(context: CodeFixContext): CodeFixAction[] | undefined {
4141
const sourceFile = context.sourceFile;
42-
const targetKind = Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures.code === context.errorCode ? SyntaxKind.CallExpression : SyntaxKind.NewExpression;
42+
const targetKind = Diagnostics.This_expression_is_not_callable.code === context.errorCode ? SyntaxKind.CallExpression : SyntaxKind.NewExpression;
4343
const node = findAncestor(getTokenAtPosition(sourceFile, context.span.start), a => a.kind === targetKind && a.getStart() === context.span.start && a.getEnd() === (context.span.start + context.span.length)) as CallExpression | NewExpression;
4444
if (!node) {
4545
return [];
Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,49 @@
1-
tests/cases/compiler/betterErrorForAccidentalCall.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/betterErrorForAccidentalCall.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/betterErrorForAccidentalCall.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/betterErrorForAccidentalCall.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/betterErrorForAccidentalCall.ts(13,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
1+
tests/cases/compiler/betterErrorForAccidentalCall.ts(3,1): error TS2349: This expression is not callable.
2+
Type 'String' has no call signatures.
3+
tests/cases/compiler/betterErrorForAccidentalCall.ts(5,1): error TS2349: This expression is not callable.
4+
Type 'String' has no call signatures.
5+
tests/cases/compiler/betterErrorForAccidentalCall.ts(7,1): error TS2349: This expression is not callable.
6+
Type 'String' has no call signatures.
7+
tests/cases/compiler/betterErrorForAccidentalCall.ts(10,1): error TS2349: This expression is not callable.
8+
Type 'String' has no call signatures.
9+
tests/cases/compiler/betterErrorForAccidentalCall.ts(13,1): error TS2349: This expression is not callable.
10+
Type 'String' has no call signatures.
611

712

813
==== tests/cases/compiler/betterErrorForAccidentalCall.ts (5 errors) ====
914
declare function foo(): string;
1015

1116
foo()(1 as number).toString();
1217
~~~~~~~~~~~~~~~~~~
13-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
18+
!!! error TS2349: This expression is not callable.
19+
!!! error TS2349: Type 'String' has no call signatures.
1420

1521
foo() (1 as number).toString();
1622
~~~~~~~~~~~~~~~~~~~~~
17-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
23+
!!! error TS2349: This expression is not callable.
24+
!!! error TS2349: Type 'String' has no call signatures.
1825

1926
foo()
2027
~~~~~
2128
(1 as number).toString();
2229
~~~~~~~~~~~~~
23-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
30+
!!! error TS2349: This expression is not callable.
31+
!!! error TS2349: Type 'String' has no call signatures.
2432
!!! related TS2734 tests/cases/compiler/betterErrorForAccidentalCall.ts:7:1: It is highly likely that you are missing a semicolon.
2533

2634
foo()
2735
~~~~~
2836
(1 + 2).toString();
2937
~~~~~~~~~~~
30-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
38+
!!! error TS2349: This expression is not callable.
39+
!!! error TS2349: Type 'String' has no call signatures.
3140
!!! related TS2734 tests/cases/compiler/betterErrorForAccidentalCall.ts:10:1: It is highly likely that you are missing a semicolon.
3241

3342
foo()
3443
~~~~~
3544
(<number>1).toString();
3645
~~~~~~~~~~~~~~~
37-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
46+
!!! error TS2349: This expression is not callable.
47+
!!! error TS2349: Type 'String' has no call signatures.
3848
!!! related TS2734 tests/cases/compiler/betterErrorForAccidentalCall.ts:13:1: It is highly likely that you are missing a semicolon.
3949

tests/baselines/reference/callOnInstance.errors.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
tests/cases/compiler/callOnInstance.ts(1,18): error TS2300: Duplicate identifier 'D'.
22
tests/cases/compiler/callOnInstance.ts(3,15): error TS2300: Duplicate identifier 'D'.
33
tests/cases/compiler/callOnInstance.ts(7,25): error TS2554: Expected 0 arguments, but got 1.
4-
tests/cases/compiler/callOnInstance.ts(10,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'C' has no compatible call signatures.
4+
tests/cases/compiler/callOnInstance.ts(10,1): error TS2349: This expression is not callable.
5+
Type 'C' has no call signatures.
56

67

78
==== tests/cases/compiler/callOnInstance.ts (4 errors) ====
@@ -22,4 +23,5 @@ tests/cases/compiler/callOnInstance.ts(10,1): error TS2349: Cannot invoke an exp
2223
declare class C { constructor(value: number); }
2324
(new C(1))(); // Error for calling an instance
2425
~~~~~~~~~~~~
25-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'C' has no compatible call signatures.
26+
!!! error TS2349: This expression is not callable.
27+
!!! error TS2349: Type 'C' has no call signatures.

tests/baselines/reference/computedPropertiesInDestructuring1.errors.txt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@ tests/cases/compiler/computedPropertiesInDestructuring1.ts(14,15): error TS2537:
66
tests/cases/compiler/computedPropertiesInDestructuring1.ts(15,15): error TS2537: Type '{ bar: number; }' has no matching index signature for type 'string'.
77
tests/cases/compiler/computedPropertiesInDestructuring1.ts(16,16): error TS2537: Type '{ bar: number; }' has no matching index signature for type 'string'.
88
tests/cases/compiler/computedPropertiesInDestructuring1.ts(17,16): error TS2537: Type '{ bar: number; }' has no matching index signature for type 'string'.
9-
tests/cases/compiler/computedPropertiesInDestructuring1.ts(20,8): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
9+
tests/cases/compiler/computedPropertiesInDestructuring1.ts(20,8): error TS2349: This expression is not callable.
10+
Type 'String' has no call signatures.
1011
tests/cases/compiler/computedPropertiesInDestructuring1.ts(20,8): error TS2538: Type 'any' cannot be used as an index type.
1112
tests/cases/compiler/computedPropertiesInDestructuring1.ts(21,8): error TS2538: Type 'any' cannot be used as an index type.
1213
tests/cases/compiler/computedPropertiesInDestructuring1.ts(21,12): error TS2339: Property 'toExponential' does not exist on type 'string'.
1314
tests/cases/compiler/computedPropertiesInDestructuring1.ts(24,4): error TS2537: Type '{ bar: string; }' has no matching index signature for type 'string'.
1415
tests/cases/compiler/computedPropertiesInDestructuring1.ts(28,4): error TS2537: Type '{ bar: string; }' has no matching index signature for type 'string'.
1516
tests/cases/compiler/computedPropertiesInDestructuring1.ts(30,4): error TS2537: Type '{ bar: string; }' has no matching index signature for type 'string'.
1617
tests/cases/compiler/computedPropertiesInDestructuring1.ts(31,4): error TS2537: Type '{ bar: string; }' has no matching index signature for type 'string'.
17-
tests/cases/compiler/computedPropertiesInDestructuring1.ts(33,4): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
18+
tests/cases/compiler/computedPropertiesInDestructuring1.ts(33,4): error TS2349: This expression is not callable.
19+
Type 'String' has no call signatures.
1820
tests/cases/compiler/computedPropertiesInDestructuring1.ts(33,4): error TS2538: Type 'any' cannot be used as an index type.
1921
tests/cases/compiler/computedPropertiesInDestructuring1.ts(34,4): error TS2538: Type 'any' cannot be used as an index type.
2022
tests/cases/compiler/computedPropertiesInDestructuring1.ts(34,5): error TS2365: Operator '+' cannot be applied to types '1' and '{}'.
@@ -58,7 +60,8 @@ tests/cases/compiler/computedPropertiesInDestructuring1.ts(34,5): error TS2365:
5860
// report errors on type errors in computed properties used in destructuring
5961
let [{[foo()]: bar6}] = [{bar: "bar"}];
6062
~~~~~
61-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
63+
!!! error TS2349: This expression is not callable.
64+
!!! error TS2349: Type 'String' has no call signatures.
6265
~~~~~
6366
!!! error TS2538: Type 'any' cannot be used as an index type.
6467
let [{[foo.toExponential()]: bar7}] = [{bar: "bar"}];
@@ -87,7 +90,8 @@ tests/cases/compiler/computedPropertiesInDestructuring1.ts(34,5): error TS2365:
8790

8891
[{[foo()]: bar4}] = [{bar: "bar"}];
8992
~~~~~
90-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
93+
!!! error TS2349: This expression is not callable.
94+
!!! error TS2349: Type 'String' has no call signatures.
9195
~~~~~
9296
!!! error TS2538: Type 'any' cannot be used as an index type.
9397
[{[(1 + {})]: bar4}] = [{bar: "bar"}];

0 commit comments

Comments
 (0)