Skip to content

Commit e1bc916

Browse files
committed
Merge branch 'master' into excess-property-checks-for-discriminated-unions
2 parents 97ee951 + 7a4c331 commit e1bc916

19 files changed

+971
-6
lines changed

src/compiler/checker.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16572,6 +16572,12 @@ namespace ts {
1657216572
return resolveUntypedCall(node);
1657316573
}
1657416574

16575+
if (isPotentiallyUncalledDecorator(node, callSignatures)) {
16576+
const nodeStr = getTextOfNode(node.expression, /*includeTrivia*/ false);
16577+
error(node, Diagnostics._0_accepts_too_few_arguments_to_be_used_as_a_decorator_here_Did_you_mean_to_call_it_first_and_write_0, nodeStr);
16578+
return resolveErrorCall(node);
16579+
}
16580+
1657516581
const headMessage = getDiagnosticHeadMessageForDecoratorResolution(node);
1657616582
if (!callSignatures.length) {
1657716583
let errorInfo: DiagnosticMessageChain;
@@ -16584,6 +16590,18 @@ namespace ts {
1658416590
return resolveCall(node, callSignatures, candidatesOutArray, headMessage);
1658516591
}
1658616592

16593+
/**
16594+
* Sometimes, we have a decorator that could accept zero arguments,
16595+
* but is receiving too many arguments as part of the decorator invocation.
16596+
* In those cases, a user may have meant to *call* the expression before using it as a decorator.
16597+
*/
16598+
function isPotentiallyUncalledDecorator(decorator: Decorator, signatures: Signature[]) {
16599+
return signatures.length && every(signatures, signature =>
16600+
signature.minArgumentCount === 0 &&
16601+
!signature.hasRestParameter &&
16602+
signature.parameters.length < getEffectiveArgumentCount(decorator, /*args*/ undefined, signature));
16603+
}
16604+
1658716605
/**
1658816606
* This function is similar to getResolvedSignature but is exclusively for trying to resolve JSX stateless-function component.
1658916607
* The main reason we have to use this function instead of getResolvedSignature because, the caller of this function will already check the type of openingLikeElement's tagName

src/compiler/diagnosticMessages.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,10 @@
907907
"category": "Error",
908908
"code": 1328
909909
},
910+
"'{0}' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@{0}()'?": {
911+
"category": "Error",
912+
"code": 1329
913+
},
910914

911915
"Duplicate identifier '{0}'.": {
912916
"category": "Error",
@@ -3705,6 +3709,10 @@
37053709
"category": "Message",
37063710
"code": 90027
37073711
},
3712+
"Call decorator expression.": {
3713+
"category": "Message",
3714+
"code": 90028
3715+
},
37083716

37093717
"Convert function to an ES2015 class": {
37103718
"category": "Message",

src/compiler/emitter.ts

100755100644
File mode changed.

src/compiler/transformers/module/module.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -861,10 +861,10 @@ namespace ts {
861861
if (original && hasAssociatedEndOfDeclarationMarker(original)) {
862862
// Defer exports until we encounter an EndOfDeclarationMarker node
863863
const id = getOriginalNodeId(node);
864-
deferredExports[id] = appendExportStatement(deferredExports[id], createIdentifier("default"), node.expression, /*location*/ node, /*allowComments*/ true);
864+
deferredExports[id] = appendExportStatement(deferredExports[id], createIdentifier("default"), visitNode(node.expression, importCallExpressionVisitor), /*location*/ node, /*allowComments*/ true);
865865
}
866866
else {
867-
statements = appendExportStatement(statements, createIdentifier("default"), node.expression, /*location*/ node, /*allowComments*/ true);
867+
statements = appendExportStatement(statements, createIdentifier("default"), visitNode(node.expression, importCallExpressionVisitor), /*location*/ node, /*allowComments*/ true);
868868
}
869869

870870
return singleOrMany(statements);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* @internal */
2+
namespace ts.codefix {
3+
registerCodeFix({
4+
errorCodes: [Diagnostics._0_accepts_too_few_arguments_to_be_used_as_a_decorator_here_Did_you_mean_to_call_it_first_and_write_0.code],
5+
getCodeActions: (context: CodeFixContext) => {
6+
const sourceFile = context.sourceFile;
7+
const token = getTokenAtPosition(sourceFile, context.span.start, /*includeJsDocComment*/ false);
8+
const decorator = getAncestor(token, SyntaxKind.Decorator) as Decorator;
9+
Debug.assert(!!decorator, "Expected position to be owned by a decorator.");
10+
const replacement = createCall(decorator.expression, /*typeArguments*/ undefined, /*argumentsArray*/ undefined);
11+
const changeTracker = textChanges.ChangeTracker.fromContext(context);
12+
changeTracker.replaceNode(sourceFile, decorator.expression, replacement);
13+
14+
return [{
15+
description: getLocaleSpecificMessage(Diagnostics.Call_decorator_expression),
16+
changes: changeTracker.getChanges()
17+
}];
18+
}
19+
});
20+
}

src/services/codefixes/fixes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/// <reference path="addMissingInvocationForDecorator.ts" />
12
/// <reference path="correctQualifiedNameToIndexedAccessType.ts" />
23
/// <reference path="fixClassIncorrectlyImplementsInterface.ts" />
34
/// <reference path="fixAddMissingMember.ts" />
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
tests/cases/conformance/decorators/class/method/decoratorOnClassMethod6.ts(4,5): error TS1241: Unable to resolve signature of method decorator when called as an expression.
1+
tests/cases/conformance/decorators/class/method/decoratorOnClassMethod6.ts(4,5): error TS1329: 'dec' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@dec()'?
22

33

44
==== tests/cases/conformance/decorators/class/method/decoratorOnClassMethod6.ts (1 errors) ====
@@ -7,5 +7,5 @@ tests/cases/conformance/decorators/class/method/decoratorOnClassMethod6.ts(4,5):
77
class C {
88
@dec ["method"]() {}
99
~~~~
10-
!!! error TS1241: Unable to resolve signature of method decorator when called as an expression.
10+
!!! error TS1329: 'dec' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@dec()'?
1111
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
tests/cases/conformance/decorators/class/property/decoratorOnClassProperty11.ts(4,5): error TS1240: Unable to resolve signature of property decorator when called as an expression.
1+
tests/cases/conformance/decorators/class/property/decoratorOnClassProperty11.ts(4,5): error TS1329: 'dec' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@dec()'?
22

33

44
==== tests/cases/conformance/decorators/class/property/decoratorOnClassProperty11.ts (1 errors) ====
@@ -7,5 +7,5 @@ tests/cases/conformance/decorators/class/property/decoratorOnClassProperty11.ts(
77
class C {
88
@dec prop;
99
~~~~
10-
!!! error TS1240: Unable to resolve signature of property decorator when called as an expression.
10+
!!! error TS1329: 'dec' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@dec()'?
1111
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
tests/cases/compiler/dynamicImportInDefaultExportExpression.ts(3,23): error TS2307: Cannot find module './foo2'.
2+
3+
4+
==== tests/cases/compiler/dynamicImportInDefaultExportExpression.ts (1 errors) ====
5+
export default {
6+
getInstance: function () {
7+
return import('./foo2');
8+
~~~~~~~~
9+
!!! error TS2307: Cannot find module './foo2'.
10+
}
11+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//// [dynamicImportInDefaultExportExpression.ts]
2+
export default {
3+
getInstance: function () {
4+
return import('./foo2');
5+
}
6+
}
7+
8+
//// [dynamicImportInDefaultExportExpression.js]
9+
"use strict";
10+
exports.__esModule = true;
11+
exports["default"] = {
12+
getInstance: function () {
13+
return Promise.resolve().then(function () { return require('./foo2'); });
14+
}
15+
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
=== tests/cases/compiler/dynamicImportInDefaultExportExpression.ts ===
2+
export default {
3+
getInstance: function () {
4+
>getInstance : Symbol(getInstance, Decl(dynamicImportInDefaultExportExpression.ts, 0, 16))
5+
6+
return import('./foo2');
7+
}
8+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
=== tests/cases/compiler/dynamicImportInDefaultExportExpression.ts ===
2+
export default {
3+
>{ getInstance: function () { return import('./foo2'); }} : { getInstance: () => Promise<any>; }
4+
5+
getInstance: function () {
6+
>getInstance : () => Promise<any>
7+
>function () { return import('./foo2'); } : () => Promise<any>
8+
9+
return import('./foo2');
10+
>import('./foo2') : Promise<any>
11+
>'./foo2' : "./foo2"
12+
}
13+
}
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
tests/cases/compiler/potentiallyUncalledDecorators.ts(4,5): error TS1329: 'Input' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@Input()'?
2+
tests/cases/compiler/potentiallyUncalledDecorators.ts(35,1): error TS1329: 'noArgs' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@noArgs()'?
3+
tests/cases/compiler/potentiallyUncalledDecorators.ts(37,5): error TS1329: 'noArgs' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@noArgs()'?
4+
tests/cases/compiler/potentiallyUncalledDecorators.ts(38,5): error TS1329: 'noArgs' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@noArgs()'?
5+
tests/cases/compiler/potentiallyUncalledDecorators.ts(41,1): error TS1238: Unable to resolve signature of class decorator when called as an expression.
6+
Type 'OmniDecorator' is not assignable to type 'typeof B'.
7+
Type 'OmniDecorator' provides no match for the signature 'new (): B'.
8+
tests/cases/compiler/potentiallyUncalledDecorators.ts(43,5): error TS1236: The return type of a property decorator function must be either 'void' or 'any'.
9+
Unable to resolve signature of property decorator when called as an expression.
10+
tests/cases/compiler/potentiallyUncalledDecorators.ts(44,5): error TS1241: Unable to resolve signature of method decorator when called as an expression.
11+
Type 'OmniDecorator' has no properties in common with type 'TypedPropertyDescriptor<() => void>'.
12+
tests/cases/compiler/potentiallyUncalledDecorators.ts(47,1): error TS1238: Unable to resolve signature of class decorator when called as an expression.
13+
Type 'OmniDecorator' is not assignable to type 'typeof C'.
14+
Type 'OmniDecorator' provides no match for the signature 'new (): C'.
15+
tests/cases/compiler/potentiallyUncalledDecorators.ts(49,5): error TS1329: 'oneOptional' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@oneOptional()'?
16+
tests/cases/compiler/potentiallyUncalledDecorators.ts(50,5): error TS1329: 'oneOptional' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@oneOptional()'?
17+
tests/cases/compiler/potentiallyUncalledDecorators.ts(53,1): error TS1238: Unable to resolve signature of class decorator when called as an expression.
18+
Type 'OmniDecorator' is not assignable to type 'typeof D'.
19+
Type 'OmniDecorator' provides no match for the signature 'new (): D'.
20+
tests/cases/compiler/potentiallyUncalledDecorators.ts(55,5): error TS1236: The return type of a property decorator function must be either 'void' or 'any'.
21+
Unable to resolve signature of property decorator when called as an expression.
22+
tests/cases/compiler/potentiallyUncalledDecorators.ts(56,5): error TS1241: Unable to resolve signature of method decorator when called as an expression.
23+
Type 'OmniDecorator' has no properties in common with type 'TypedPropertyDescriptor<() => void>'.
24+
tests/cases/compiler/potentiallyUncalledDecorators.ts(59,1): error TS1238: Unable to resolve signature of class decorator when called as an expression.
25+
Type 'OmniDecorator' is not assignable to type 'typeof E'.
26+
Type 'OmniDecorator' provides no match for the signature 'new (): E'.
27+
tests/cases/compiler/potentiallyUncalledDecorators.ts(61,5): error TS1236: The return type of a property decorator function must be either 'void' or 'any'.
28+
Unable to resolve signature of property decorator when called as an expression.
29+
tests/cases/compiler/potentiallyUncalledDecorators.ts(62,5): error TS1241: Unable to resolve signature of method decorator when called as an expression.
30+
Type 'OmniDecorator' has no properties in common with type 'TypedPropertyDescriptor<() => void>'.
31+
tests/cases/compiler/potentiallyUncalledDecorators.ts(65,1): error TS1238: Unable to resolve signature of class decorator when called as an expression.
32+
Type 'OmniDecorator' is not assignable to type 'typeof F'.
33+
Type 'OmniDecorator' provides no match for the signature 'new (): F'.
34+
tests/cases/compiler/potentiallyUncalledDecorators.ts(67,5): error TS1236: The return type of a property decorator function must be either 'void' or 'any'.
35+
Unable to resolve signature of property decorator when called as an expression.
36+
tests/cases/compiler/potentiallyUncalledDecorators.ts(68,5): error TS1241: Unable to resolve signature of method decorator when called as an expression.
37+
Type 'OmniDecorator' has no properties in common with type 'TypedPropertyDescriptor<() => void>'.
38+
39+
40+
==== tests/cases/compiler/potentiallyUncalledDecorators.ts (19 errors) ====
41+
// Angular-style Input/Output API:
42+
declare function Input(bindingPropertyName?: string): any;
43+
class FooComponent {
44+
@Input foo: string;
45+
~~~~~~
46+
!!! error TS1329: 'Input' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@Input()'?
47+
}
48+
49+
// Glimmer-style tracked API:
50+
declare const tracked: PropertyDecorator & { (...watchedProperties: string[]): any; }
51+
52+
class Person {
53+
@tracked person; any;
54+
}
55+
56+
class MultiplyByTwo {
57+
args: any;
58+
@tracked('args')
59+
get multiplied() {
60+
return this.args.number * 2;
61+
}
62+
}
63+
64+
// Other fun stuff.
65+
66+
interface OmniDecorator extends MethodDecorator, ClassDecorator, PropertyDecorator {
67+
}
68+
69+
declare function noArgs(): OmniDecorator;
70+
declare function allRest(...args: any[]): OmniDecorator;
71+
declare function oneOptional(x?: any): OmniDecorator;
72+
declare function twoOptional(x?: any, y?: any): OmniDecorator;
73+
declare function threeOptional(x?: any, y?: any, z?: any): OmniDecorator;
74+
declare function oneOptionalWithRest(x?: any, ...args: any[]): OmniDecorator;
75+
declare const anyDec: any;
76+
77+
@noArgs
78+
~~~~~~~
79+
!!! error TS1329: 'noArgs' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@noArgs()'?
80+
class A {
81+
@noArgs foo: any;
82+
~~~~~~~
83+
!!! error TS1329: 'noArgs' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@noArgs()'?
84+
@noArgs bar() { }
85+
~~~~~~~
86+
!!! error TS1329: 'noArgs' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@noArgs()'?
87+
}
88+
89+
@allRest
90+
~~~~~~~~
91+
!!! error TS1238: Unable to resolve signature of class decorator when called as an expression.
92+
!!! error TS1238: Type 'OmniDecorator' is not assignable to type 'typeof B'.
93+
!!! error TS1238: Type 'OmniDecorator' provides no match for the signature 'new (): B'.
94+
class B {
95+
@allRest foo: any;
96+
~~~~~~~~
97+
!!! error TS1236: The return type of a property decorator function must be either 'void' or 'any'.
98+
!!! error TS1236: Unable to resolve signature of property decorator when called as an expression.
99+
@allRest bar() { }
100+
~~~~~~~~
101+
!!! error TS1241: Unable to resolve signature of method decorator when called as an expression.
102+
!!! error TS1241: Type 'OmniDecorator' has no properties in common with type 'TypedPropertyDescriptor<() => void>'.
103+
}
104+
105+
@oneOptional
106+
~~~~~~~~~~~~
107+
!!! error TS1238: Unable to resolve signature of class decorator when called as an expression.
108+
!!! error TS1238: Type 'OmniDecorator' is not assignable to type 'typeof C'.
109+
!!! error TS1238: Type 'OmniDecorator' provides no match for the signature 'new (): C'.
110+
class C {
111+
@oneOptional foo: any;
112+
~~~~~~~~~~~~
113+
!!! error TS1329: 'oneOptional' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@oneOptional()'?
114+
@oneOptional bar() { }
115+
~~~~~~~~~~~~
116+
!!! error TS1329: 'oneOptional' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@oneOptional()'?
117+
}
118+
119+
@twoOptional
120+
~~~~~~~~~~~~
121+
!!! error TS1238: Unable to resolve signature of class decorator when called as an expression.
122+
!!! error TS1238: Type 'OmniDecorator' is not assignable to type 'typeof D'.
123+
!!! error TS1238: Type 'OmniDecorator' provides no match for the signature 'new (): D'.
124+
class D {
125+
@twoOptional foo: any;
126+
~~~~~~~~~~~~
127+
!!! error TS1236: The return type of a property decorator function must be either 'void' or 'any'.
128+
!!! error TS1236: Unable to resolve signature of property decorator when called as an expression.
129+
@twoOptional bar() { }
130+
~~~~~~~~~~~~
131+
!!! error TS1241: Unable to resolve signature of method decorator when called as an expression.
132+
!!! error TS1241: Type 'OmniDecorator' has no properties in common with type 'TypedPropertyDescriptor<() => void>'.
133+
}
134+
135+
@threeOptional
136+
~~~~~~~~~~~~~~
137+
!!! error TS1238: Unable to resolve signature of class decorator when called as an expression.
138+
!!! error TS1238: Type 'OmniDecorator' is not assignable to type 'typeof E'.
139+
!!! error TS1238: Type 'OmniDecorator' provides no match for the signature 'new (): E'.
140+
class E {
141+
@threeOptional foo: any;
142+
~~~~~~~~~~~~~~
143+
!!! error TS1236: The return type of a property decorator function must be either 'void' or 'any'.
144+
!!! error TS1236: Unable to resolve signature of property decorator when called as an expression.
145+
@threeOptional bar() { }
146+
~~~~~~~~~~~~~~
147+
!!! error TS1241: Unable to resolve signature of method decorator when called as an expression.
148+
!!! error TS1241: Type 'OmniDecorator' has no properties in common with type 'TypedPropertyDescriptor<() => void>'.
149+
}
150+
151+
@oneOptionalWithRest
152+
~~~~~~~~~~~~~~~~~~~~
153+
!!! error TS1238: Unable to resolve signature of class decorator when called as an expression.
154+
!!! error TS1238: Type 'OmniDecorator' is not assignable to type 'typeof F'.
155+
!!! error TS1238: Type 'OmniDecorator' provides no match for the signature 'new (): F'.
156+
class F {
157+
@oneOptionalWithRest foo: any;
158+
~~~~~~~~~~~~~~~~~~~~
159+
!!! error TS1236: The return type of a property decorator function must be either 'void' or 'any'.
160+
!!! error TS1236: Unable to resolve signature of property decorator when called as an expression.
161+
@oneOptionalWithRest bar() { }
162+
~~~~~~~~~~~~~~~~~~~~
163+
!!! error TS1241: Unable to resolve signature of method decorator when called as an expression.
164+
!!! error TS1241: Type 'OmniDecorator' has no properties in common with type 'TypedPropertyDescriptor<() => void>'.
165+
}
166+
167+
@anyDec
168+
class G {
169+
@anyDec foo: any;
170+
@anyDec bar() { }
171+
}
172+
173+
export { };
174+

0 commit comments

Comments
 (0)