Skip to content

Commit 8141f01

Browse files
bradzacherJamesHenry
authored andcommitted
feat(eslint-plugin): add support for object props in CallExpressions (#728)
1 parent fd6be42 commit 8141f01

File tree

3 files changed

+116
-53
lines changed

3 files changed

+116
-53
lines changed

packages/eslint-plugin/docs/rules/explicit-function-return-type.md

+7
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,13 @@ let objectPropCast = <ObjectType>{
141141

142142
declare functionWithArg(arg: () => number);
143143
functionWithArg(() => 1);
144+
145+
declare functionWithObjectArg(arg: { meth: () => number });
146+
functionWithObjectArg({
147+
meth() {
148+
return 1;
149+
},
150+
});
144151
```
145152

146153
### allowHigherOrderFunctions

packages/eslint-plugin/src/rules/explicit-function-return-type.ts

+10-9
Original file line numberDiff line numberDiff line change
@@ -118,28 +118,29 @@ export default util.createRule<Options, MessageIds>({
118118
* `const x = <Foo>{ prop: () => {} }`
119119
*/
120120
function isPropertyOfObjectWithType(
121-
parent: TSESTree.Node | undefined,
121+
property: TSESTree.Node | undefined,
122122
): boolean {
123-
if (!parent || parent.type !== AST_NODE_TYPES.Property) {
123+
if (!property || property.type !== AST_NODE_TYPES.Property) {
124124
return false;
125125
}
126-
parent = parent.parent; // this shouldn't happen, checking just in case
126+
const objectExpr = property.parent; // this shouldn't happen, checking just in case
127127
/* istanbul ignore if */ if (
128-
!parent ||
129-
parent.type !== AST_NODE_TYPES.ObjectExpression
128+
!objectExpr ||
129+
objectExpr.type !== AST_NODE_TYPES.ObjectExpression
130130
) {
131131
return false;
132132
}
133133

134-
parent = parent.parent; // this shouldn't happen, checking just in case
134+
const parent = objectExpr.parent; // this shouldn't happen, checking just in case
135135
/* istanbul ignore if */ if (!parent) {
136136
return false;
137137
}
138138

139139
return (
140140
isTypeCast(parent) ||
141141
isClassPropertyWithTypeAnnotation(parent) ||
142-
isVariableDeclaratorWithTypeAnnotation(parent)
142+
isVariableDeclaratorWithTypeAnnotation(parent) ||
143+
isFunctionArgument(parent)
143144
);
144145
}
145146

@@ -193,12 +194,12 @@ export default util.createRule<Options, MessageIds>({
193194
*/
194195
function isFunctionArgument(
195196
parent: TSESTree.Node,
196-
child: TSESTree.Node,
197+
callee?: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression,
197198
): boolean {
198199
return (
199200
parent.type === AST_NODE_TYPES.CallExpression &&
200201
// make sure this isn't an IIFE
201-
parent.callee !== child
202+
parent.callee !== callee
202203
);
203204
}
204205

packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts

+99-44
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,32 @@ new Accumulator().accumulate(() => 1);
273273
},
274274
],
275275
},
276+
{
277+
filename: 'test.ts',
278+
code: `
279+
declare function foo(arg: { meth: () => number }): void
280+
foo({
281+
meth() {
282+
return 1;
283+
},
284+
})
285+
foo({
286+
meth: function () {
287+
return 1;
288+
},
289+
})
290+
foo({
291+
meth: () => {
292+
return 1;
293+
},
294+
})
295+
`,
296+
options: [
297+
{
298+
allowTypedFunctionExpressions: true,
299+
},
300+
],
301+
},
276302
],
277303
invalid: [
278304
{
@@ -281,7 +307,7 @@ new Accumulator().accumulate(() => 1);
281307
function test() {
282308
return;
283309
}
284-
`,
310+
`,
285311
errors: [
286312
{
287313
messageId: 'missingReturnType',
@@ -296,7 +322,7 @@ function test() {
296322
var fn = function() {
297323
return 1;
298324
};
299-
`,
325+
`,
300326
errors: [
301327
{
302328
messageId: 'missingReturnType',
@@ -309,7 +335,7 @@ var fn = function() {
309335
filename: 'test.ts',
310336
code: `
311337
var arrowFn = () => 'test';
312-
`,
338+
`,
313339
errors: [
314340
{
315341
messageId: 'missingReturnType',
@@ -332,7 +358,7 @@ class Test {
332358
}
333359
arrow = () => 'arrow';
334360
}
335-
`,
361+
`,
336362
errors: [
337363
{
338364
messageId: 'missingReturnType',
@@ -353,21 +379,23 @@ class Test {
353379
},
354380
{
355381
filename: 'test.ts',
356-
code: `function test() {
357-
return;
358-
}`,
382+
code: `
383+
function test() {
384+
return;
385+
}
386+
`,
359387
options: [{ allowExpressions: true }],
360388
errors: [
361389
{
362390
messageId: 'missingReturnType',
363-
line: 1,
391+
line: 2,
364392
column: 1,
365393
},
366394
],
367395
},
368396
{
369397
filename: 'test.ts',
370-
code: `const foo = () => {};`,
398+
code: 'const foo = () => {};',
371399
options: [{ allowExpressions: true }],
372400
errors: [
373401
{
@@ -379,7 +407,7 @@ class Test {
379407
},
380408
{
381409
filename: 'test.ts',
382-
code: `const foo = function() {};`,
410+
code: 'const foo = function() {};',
383411
options: [{ allowExpressions: true }],
384412
errors: [
385413
{
@@ -391,7 +419,7 @@ class Test {
391419
},
392420
{
393421
filename: 'test.ts',
394-
code: `var arrowFn = () => 'test';`,
422+
code: "var arrowFn = () => 'test';",
395423
options: [{ allowTypedFunctionExpressions: true }],
396424
errors: [
397425
{
@@ -403,7 +431,7 @@ class Test {
403431
},
404432
{
405433
filename: 'test.ts',
406-
code: `var funcExpr = function() { return 'test'; };`,
434+
code: "var funcExpr = function() { return 'test'; };",
407435
options: [{ allowTypedFunctionExpressions: true }],
408436
errors: [
409437
{
@@ -416,7 +444,7 @@ class Test {
416444

417445
{
418446
filename: 'test.ts',
419-
code: `const x = (() => {}) as Foo`,
447+
code: 'const x = (() => {}) as Foo',
420448
options: [{ allowTypedFunctionExpressions: false }],
421449
errors: [
422450
{
@@ -459,84 +487,72 @@ const x: Foo = {
459487
},
460488
{
461489
filename: 'test.ts',
462-
code: `
463-
() => () => {};
464-
`,
490+
code: '() => () => {};',
465491
options: [{ allowHigherOrderFunctions: true }],
466492
errors: [
467493
{
468494
messageId: 'missingReturnType',
469-
line: 2,
495+
line: 1,
470496
column: 7,
471497
},
472498
],
473499
},
474500
{
475501
filename: 'test.ts',
476-
code: `
477-
() => function () {};
478-
`,
502+
code: '() => function () {};',
479503
options: [{ allowHigherOrderFunctions: true }],
480504
errors: [
481505
{
482506
messageId: 'missingReturnType',
483-
line: 2,
507+
line: 1,
484508
column: 7,
485509
},
486510
],
487511
},
488512
{
489513
filename: 'test.ts',
490-
code: `
491-
() => { return () => {} };
492-
`,
514+
code: '() => { return () => {} };',
493515
options: [{ allowHigherOrderFunctions: true }],
494516
errors: [
495517
{
496518
messageId: 'missingReturnType',
497-
line: 2,
519+
line: 1,
498520
column: 16,
499521
},
500522
],
501523
},
502524
{
503525
filename: 'test.ts',
504-
code: `
505-
() => { return function () {} };
506-
`,
526+
code: '() => { return function () {} };',
507527
options: [{ allowHigherOrderFunctions: true }],
508528
errors: [
509529
{
510530
messageId: 'missingReturnType',
511-
line: 2,
531+
line: 1,
512532
column: 16,
513533
},
514534
],
515535
},
516536
{
517537
filename: 'test.ts',
518-
code: `
519-
function fn() { return () => {} };
520-
`,
538+
code: 'function fn() { return () => {} };',
521539
options: [{ allowHigherOrderFunctions: true }],
522540
errors: [
523541
{
524542
messageId: 'missingReturnType',
525-
line: 2,
543+
line: 1,
526544
column: 24,
527545
},
528546
],
529547
},
530548
{
531549
filename: 'test.ts',
532-
code: `
533-
function fn() { return function () {} };
534-
`,
550+
code: 'function fn() { return function () {} };',
535551
options: [{ allowHigherOrderFunctions: true }],
536552
errors: [
537553
{
538554
messageId: 'missingReturnType',
539-
line: 2,
555+
line: 1,
540556
column: 24,
541557
},
542558
],
@@ -566,14 +582,12 @@ function FunctionDeclaration() {
566582
},
567583
{
568584
filename: 'test.ts',
569-
code: `
570-
() => () => { return () => { return; } };
571-
`,
585+
code: '() => () => { return () => { return; } };',
572586
options: [{ allowHigherOrderFunctions: true }],
573587
errors: [
574588
{
575589
messageId: 'missingReturnType',
576-
line: 2,
590+
line: 1,
577591
column: 22,
578592
},
579593
],
@@ -643,10 +657,41 @@ new Accumulator().accumulate(() => 1);
643657
},
644658
],
645659
},
660+
{
661+
filename: 'test.ts',
662+
code: '(() => true)()',
663+
options: [
664+
{
665+
allowTypedFunctionExpressions: false,
666+
},
667+
],
668+
errors: [
669+
{
670+
messageId: 'missingReturnType',
671+
line: 1,
672+
column: 2,
673+
},
674+
],
675+
},
646676
{
647677
filename: 'test.ts',
648678
code: `
649-
(() => true)()
679+
declare function foo(arg: { meth: () => number }): void
680+
foo({
681+
meth() {
682+
return 1;
683+
},
684+
})
685+
foo({
686+
meth: function () {
687+
return 1;
688+
},
689+
})
690+
foo({
691+
meth: () => {
692+
return 1;
693+
},
694+
})
650695
`,
651696
options: [
652697
{
@@ -656,8 +701,18 @@ new Accumulator().accumulate(() => 1);
656701
errors: [
657702
{
658703
messageId: 'missingReturnType',
659-
line: 2,
660-
column: 2,
704+
line: 4,
705+
column: 7,
706+
},
707+
{
708+
messageId: 'missingReturnType',
709+
line: 9,
710+
column: 9,
711+
},
712+
{
713+
messageId: 'missingReturnType',
714+
line: 14,
715+
column: 9,
661716
},
662717
],
663718
},

0 commit comments

Comments
 (0)