Skip to content

Commit 76f25fe

Browse files
committed
Clarify error message when an accessor is invoked.
1 parent ebebc9f commit 76f25fe

File tree

4 files changed

+64
-13
lines changed

4 files changed

+64
-13
lines changed

src/compiler/checker.ts

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,17 @@ namespace ts {
242242
const parsed = getParseTreeNode(node, isFunctionLike);
243243
return parsed ? isImplementationOfOverload(parsed) : undefined;
244244
},
245-
getImmediateAliasedSymbol,
245+
getImmediateAliasedSymbol: symbol => {
246+
Debug.assert((symbol.flags & SymbolFlags.Alias) !== 0, "Should only get Alias here.");
247+
const links = getSymbolLinks(symbol);
248+
if (!links.immediateTarget) {
249+
const node = getDeclarationOfAliasSymbol(symbol);
250+
if (!node) return Debug.fail();
251+
links.immediateTarget = getTargetOfAliasDeclaration(node, /*dontRecursivelyResolve*/ true);
252+
}
253+
254+
return links.immediateTarget;
255+
},
246256
getAliasedSymbol: resolveAlias,
247257
getEmitResolver,
248258
getExportsOfModule: getExportsOfModuleAsArray,
@@ -20646,13 +20656,47 @@ namespace ts {
2064620656
}
2064720657
else {
2064820658
let relatedInformation: DiagnosticRelatedInformation | undefined;
20659+
let propertyName: string | undefined;
20660+
let propertyAccessorText: string | undefined;
2064920661
if (node.arguments.length === 1) {
2065020662
const text = getSourceFileOfNode(node).text;
2065120663
if (isLineBreak(text.charCodeAt(skipTrivia(text, node.expression.end, /* stopAfterLineBreak */ true) - 1))) {
2065220664
relatedInformation = createDiagnosticForNode(node.expression, Diagnostics.It_is_highly_likely_that_you_are_missing_a_semicolon);
2065320665
}
2065420666
}
20655-
invocationError(node, apparentType, SignatureKind.Call, relatedInformation);
20667+
else if (node.expression.kind === SyntaxKind.PropertyAccessExpression) {
20668+
const propertyAccess = node.expression as PropertyAccessExpression;
20669+
const symbol = getSymbolOfEntityNameOrPropertyAccessExpression(propertyAccess);
20670+
20671+
// Handle union types with non-function-like signatures.
20672+
if (symbol) {
20673+
const links = getSymbolLinks(symbol);
20674+
const isObjectUnionOrIntersection = links && links.type && (
20675+
(links.type.flags & (TypeFlags.Union | TypeFlags.Intersection | TypeFlags.Object)) !== 0
20676+
) || false;
20677+
20678+
let invokable = isObjectUnionOrIntersection;
20679+
if (isObjectUnionOrIntersection) {
20680+
if (links && links.type && (links.type.flags & TypeFlags.Object)) {
20681+
const resolvedType = links.type as ObjectType;
20682+
invokable = (resolvedType.callSignatures && resolvedType.callSignatures.length !== 0) || false;
20683+
}
20684+
else {
20685+
const resolvedType = links.type as UnionOrIntersectionType;
20686+
invokable = every(resolvedType.types, ty => (ty as ResolvedType).callSignatures && (ty as ResolvedType).callSignatures.length !== 0);
20687+
}
20688+
}
20689+
20690+
if (!invokable) {
20691+
const file = getSourceFileOfNode(node);
20692+
20693+
propertyName = propertyAccess.name.escapedText.toString();
20694+
propertyAccessorText = createPrinter().printNode(EmitHint.Expression, propertyAccess, file);
20695+
}
20696+
}
20697+
}
20698+
20699+
invocationError(node, apparentType, SignatureKind.Call, relatedInformation, propertyName, propertyAccessorText);
2065620700
}
2065720701
return resolveErrorCall(node);
2065820702
}
@@ -20822,11 +20866,14 @@ namespace ts {
2082220866
return true;
2082320867
}
2082420868

20825-
function invocationError(node: Node, apparentType: Type, kind: SignatureKind, relatedInformation?: DiagnosticRelatedInformation) {
20869+
function invocationError(node: Node, apparentType: Type, kind: SignatureKind, relatedInformation?: DiagnosticRelatedInformation, propertyName?: string, didYouMean?: string) {
2082620870
const diagnostic = error(node, (kind === SignatureKind.Call ?
20827-
Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures :
20871+
(propertyName === undefined ?
20872+
Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures :
20873+
Diagnostics.Cannot_invoke_expression_1_which_is_a_property_and_has_the_type_0_which_has_no_compatible_call_signature_Did_you_mean_2
20874+
) :
2082820875
Diagnostics.Cannot_use_new_with_an_expression_whose_type_lacks_a_call_or_construct_signature
20829-
), typeToString(apparentType));
20876+
), typeToString(apparentType), propertyName, didYouMean);
2083020877
invocationErrorRecovery(apparentType, kind, relatedInformation ? addRelatedInfo(diagnostic, relatedInformation) : diagnostic);
2083120878
}
2083220879

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2549,6 +2549,10 @@
25492549
"category": "Error",
25502550
"code": 2747
25512551
},
2552+
"Cannot invoke expression `{1}`, which is a property and has the type `{0}` which has no compatible call signature. Did you mean `{2}`": {
2553+
"category": "Error",
2554+
"code": 2748
2555+
},
25522556

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

tests/baselines/reference/instancePropertiesInheritedIntoClassType.errors.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts(4,13): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
22
tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts(7,13): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
3-
tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts(19,14): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'Number' has no compatible call signatures.
3+
tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts(19,14): error TS2748: Cannot invoke expression `y`, which is a property and has the type `Number` which has no compatible call signature. Did you mean `d.y`
44
tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts(26,13): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
55
tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts(29,13): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
6-
tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts(41,14): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
6+
tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts(41,14): error TS2748: Cannot invoke expression `y`, which is a property and has the type `String` which has no compatible call signature. Did you mean `d.y`
77

88

99
==== tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts (6 errors) ====
@@ -31,7 +31,7 @@ tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIn
3131
r.y = 4;
3232
var r6 = d.y(); // error
3333
~~~~~
34-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'Number' has no compatible call signatures.
34+
!!! error TS2748: Cannot invoke expression `y`, which is a property and has the type `Number` which has no compatible call signature. Did you mean `d.y`
3535

3636
}
3737

@@ -59,5 +59,5 @@ tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIn
5959
r.y = '';
6060
var r6 = d.y(); // error
6161
~~~~~
62-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
62+
!!! error TS2748: Cannot invoke expression `y`, which is a property and has the type `String` which has no compatible call signature. Did you mean `d.y`
6363
}

tests/baselines/reference/instancePropertyInClassType.errors.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts(4,13): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
22
tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts(7,13): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
3-
tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts(17,14): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'Number' has no compatible call signatures.
3+
tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts(17,14): error TS2748: Cannot invoke expression `y`, which is a property and has the type `Number` which has no compatible call signature. Did you mean `c.y`
44
tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts(24,13): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
55
tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts(27,13): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
6-
tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts(37,14): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
6+
tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts(37,14): error TS2748: Cannot invoke expression `y`, which is a property and has the type `String` which has no compatible call signature. Did you mean `c.y`
77

88

99
==== tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts (6 errors) ====
@@ -29,7 +29,7 @@ tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.t
2929
r.y = 4;
3030
var r6 = c.y(); // error
3131
~~~~~
32-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'Number' has no compatible call signatures.
32+
!!! error TS2748: Cannot invoke expression `y`, which is a property and has the type `Number` which has no compatible call signature. Did you mean `c.y`
3333

3434
}
3535

@@ -55,5 +55,5 @@ tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.t
5555
r.y = '';
5656
var r6 = c.y(); // error
5757
~~~~~
58-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
58+
!!! error TS2748: Cannot invoke expression `y`, which is a property and has the type `String` which has no compatible call signature. Did you mean `c.y`
5959
}

0 commit comments

Comments
 (0)