Skip to content

Commit bea6b92

Browse files
gilbsgilbsbradzacher
authored andcommitted
feat(eslint-plugin): allow explicit variable type with arrow functions (typescript-eslint#260)
Fixes typescript-eslint#149 Not sure if this is really acceptable though. Please tell me if it has some edge cases I didn't see or if it's just too broad.
1 parent c7db594 commit bea6b92

File tree

3 files changed

+95
-9
lines changed

3 files changed

+95
-9
lines changed

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,20 @@ node.addEventListener('click', function() {});
8484
const foo = arr.map(i => i * i);
8585
```
8686

87+
### allowTypedFunctionExpressions
88+
89+
Examples of additional **correct** code for this rule with `{ allowTypedFunctionExpressions: true }`:
90+
91+
```ts
92+
type FuncType = () => string;
93+
94+
let arrowFn: FuncType = () => 'test';
95+
96+
let funcExpr: FuncType = function() {
97+
return 'test';
98+
};
99+
```
100+
87101
## When Not To Use It
88102

89103
If you don't wish to prevent calling code from using function return values in unexpected ways, then

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

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as util from '../util';
44
type Options = [
55
{
66
allowExpressions?: boolean;
7+
allowTypedFunctionExpressions?: boolean;
78
}
89
];
910
type MessageIds = 'missingReturnType';
@@ -28,6 +29,9 @@ export default util.createRule<Options, MessageIds>({
2829
allowExpressions: {
2930
type: 'boolean',
3031
},
32+
allowTypedFunctionExpressions: {
33+
type: 'boolean',
34+
},
3135
},
3236
additionalProperties: false,
3337
},
@@ -36,27 +40,41 @@ export default util.createRule<Options, MessageIds>({
3640
defaultOptions: [
3741
{
3842
allowExpressions: true,
43+
allowTypedFunctionExpressions: false,
3944
},
4045
],
4146
create(context, [options]) {
4247
/**
43-
* Checks if the parent of a function expression is a constructor.
44-
* @param parent The parent of a function expression node
48+
* Checks if a node is a constructor.
49+
* @param node The node to check
50+
*/
51+
function isConstructor(node: TSESTree.Node): boolean {
52+
return (
53+
node.type === AST_NODE_TYPES.MethodDefinition &&
54+
node.kind === 'constructor'
55+
);
56+
}
57+
58+
/**
59+
* Checks if a node is a setter.
60+
* @param parent The node to check
4561
*/
46-
function isConstructor(parent: TSESTree.Node): boolean {
62+
function isSetter(node: TSESTree.Node): boolean {
4763
return (
48-
parent.type === AST_NODE_TYPES.MethodDefinition &&
49-
parent.kind === 'constructor'
64+
node.type === AST_NODE_TYPES.MethodDefinition && node.kind === 'set'
5065
);
5166
}
5267

5368
/**
54-
* Checks if the parent of a function expression is a setter.
55-
* @param parent The parent of a function expression node
69+
* Checks if a node is a variable declarator with a type annotation.
70+
* @param node The node to check
5671
*/
57-
function isSetter(parent: TSESTree.Node): boolean {
72+
function isVariableDeclaratorWithTypeAnnotation(
73+
node: TSESTree.Node,
74+
): boolean {
5875
return (
59-
parent.type === AST_NODE_TYPES.MethodDefinition && parent.kind === 'set'
76+
node.type === AST_NODE_TYPES.VariableDeclarator &&
77+
!!node.id.typeAnnotation
6078
);
6179
}
6280

@@ -103,6 +121,14 @@ export default util.createRule<Options, MessageIds>({
103121
return;
104122
}
105123

124+
if (
125+
options.allowTypedFunctionExpressions &&
126+
node.parent &&
127+
isVariableDeclaratorWithTypeAnnotation(node.parent)
128+
) {
129+
return;
130+
}
131+
106132
checkFunctionReturnType(node);
107133
}
108134

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,28 @@ function test() {
9292
},
9393
],
9494
},
95+
{
96+
filename: 'test.ts',
97+
code: `
98+
var arrowFn: Foo = () => 'test';
99+
`,
100+
options: [
101+
{
102+
allowTypedFunctionExpressions: true,
103+
},
104+
],
105+
},
106+
{
107+
filename: 'test.ts',
108+
code: `
109+
var funcExpr: Foo = function() { return 'test'; };
110+
`,
111+
options: [
112+
{
113+
allowTypedFunctionExpressions: true,
114+
},
115+
],
116+
},
95117
],
96118
invalid: [
97119
{
@@ -188,5 +210,29 @@ class Test {
188210
},
189211
],
190212
},
213+
{
214+
filename: 'test.ts',
215+
code: `var arrowFn = () => 'test';`,
216+
options: [{ allowTypedFunctionExpressions: true }],
217+
errors: [
218+
{
219+
messageId: 'missingReturnType',
220+
line: 1,
221+
column: 15,
222+
},
223+
],
224+
},
225+
{
226+
filename: 'test.ts',
227+
code: `var funcExpr = function() { return 'test'; };`,
228+
options: [{ allowTypedFunctionExpressions: true }],
229+
errors: [
230+
{
231+
messageId: 'missingReturnType',
232+
line: 1,
233+
column: 16,
234+
},
235+
],
236+
},
191237
],
192238
});

0 commit comments

Comments
 (0)