explicit-function-return-type
Require explicit return types on functions and class methods.
This rule requires type information to run.
Functions in TypeScript often don't need to be given an explicit return type annotation. Leaving off the return type is less code to read or write and allows the compiler to infer it from the contents of the function.
However, explicit return types do make it visually more clear what type is returned by a function. They can also speed up TypeScript type checking performance in large codebases with many large functions.
This rule enforces that functions do have an explicit return type annotation.
module.exports = {
"rules": {
"@typescript-eslint/explicit-function-return-type": "error"
}
};
Try this rule in the playground ↗
Examples
- ❌ Incorrect
- ✅ Correct
// Should indicate that no value is returned (void)
function test() {
return;
}
// Should indicate that a number is returned
var fn = function () {
return 1;
};
// Should indicate that a string is returned
var arrowFn = () => 'test';
class Test {
// Should indicate that no value is returned (void)
method() {
return;
}
}
Open in Playground// No return value should be expected (void)
function test(): void {
return;
}
// A return value of type number
var fn = function (): number {
return 1;
};
// A return value of type string
var arrowFn = (): string => 'test';
class Test {
// No return value should be expected (void)
method(): void {
return;
}
}
Open in PlaygroundOptions
This rule accepts the following options:
type Options = [
{
/** Whether to allow arrow functions that start with the `void` keyword. */
allowConciseArrowFunctionExpressionsStartingWithVoid?: boolean;
/** Whether to ignore arrow functions immediately returning a `as const` value. */
allowDirectConstAssertionInArrowFunctions?: boolean;
/** Whether to ignore function expressions (functions which are not part of a declaration). */
allowExpressions?: boolean;
/** Whether to ignore functions that don't have generic type parameters. */
allowFunctionsWithoutTypeParameters?: boolean;
/** Whether to ignore functions immediately returning another function expression. */
allowHigherOrderFunctions?: boolean;
/** Whether to ignore immediately invoked function expressions (IIFEs). */
allowIIFEs?: boolean;
/** Whether to ignore type annotations on the variable of function expressions. */
allowTypedFunctionExpressions?: boolean;
/** An array of function/method names that will not have their arguments or return values checked. */
allowedNames?: string[];
},
];
const defaultOptions: Options = [
{
allowExpressions: false,
allowTypedFunctionExpressions: true,
allowHigherOrderFunctions: true,
allowDirectConstAssertionInArrowFunctions: true,
allowConciseArrowFunctionExpressionsStartingWithVoid: false,
allowFunctionsWithoutTypeParameters: false,
allowedNames: [],
allowIIFEs: false,
},
];
Configuring in a mixed JS/TS codebase
If you are working on a codebase within which you lint non-TypeScript code (i.e. .js
/.mjs
/.cjs
/.jsx
), you should ensure that you should use ESLint overrides
to only enable the rule on .ts
/.mts
/.cts
/.tsx
files. If you don't, then you will get unfixable lint errors reported within .js
/.mjs
/.cjs
/.jsx
files.
{
"rules": {
// disable the rule for all files
"@typescript-eslint/explicit-function-return-type": "off",
},
"overrides": [
{
// enable the rule specifically for TypeScript files
"files": ["*.ts", "*.mts", "*.cts", "*.tsx"],
"rules": {
"@typescript-eslint/explicit-function-return-type": "error",
},
},
],
}
allowExpressions
Examples of code for this rule with { allowExpressions: true }
:
- ❌ Incorrect
- ✅ Correct
function test() {}
const fn = () => {};
export default () => {};
Open in Playgroundnode.addEventListener('click', () => {});
node.addEventListener('click', function () {});
const foo = arr.map(i => i * i);
Open in PlaygroundallowTypedFunctionExpressions
Examples of code for this rule with { allowTypedFunctionExpressions: true }
:
- ❌ Incorrect
- ✅ Correct
let arrowFn = () => 'test';
let funcExpr = function () {
return 'test';
};
let objectProp = {
foo: () => 1,
};
Open in Playgroundtype FuncType = () => string;
let arrowFn: FuncType = () => 'test';
let funcExpr: FuncType = function () {
return 'test';
};
let asTyped = (() => '') as () => string;
let castTyped = <() => string>(() => '');
interface ObjectType {
foo(): number;
}
let objectProp: ObjectType = {
foo: () => 1,
};
let objectPropAs = {
foo: () => 1,
} as ObjectType;
let objectPropCast = <ObjectType>{
foo: () => 1,
};
declare function functionWithArg(arg: () => number);
functionWithArg(() => 1);
declare function functionWithObjectArg(arg: { method: () => number });
functionWithObjectArg({
method() {
return 1;
},
});
Open in PlaygroundallowHigherOrderFunctions
Examples of code for this rule with { allowHigherOrderFunctions: true }
:
- ❌ Incorrect
- ✅ Correct
var arrowFn = () => () => {};
function fn() {
return function () {};
}
Open in Playgroundvar arrowFn = () => (): void => {};
function fn() {
return function (): void {};
}
Open in PlaygroundallowDirectConstAssertionInArrowFunctions
Examples of code for this rule with { allowDirectConstAssertionInArrowFunctions: true }
:
- ❌ Incorrect
- ✅ Correct
const func = (value: number) => ({ type: 'X', value }) as any;
const func = (value: number) => ({ type: 'X', value }) as Action;
Open in Playgroundconst func = (value: number) => ({ foo: 'bar', value }) as const;
const func = () => x as const;
Open in PlaygroundallowConciseArrowFunctionExpressionsStartingWithVoid
Examples of code for this rule with { allowConciseArrowFunctionExpressionsStartingWithVoid: true }
:
- ❌ Incorrect
- ✅ Correct
var join = (a: string, b: string) => `${a}${b}`;
const log = (message: string) => {
console.log(message);
};
Open in Playgroundvar log = (message: string) => void console.log(message);
Open in PlaygroundallowFunctionsWithoutTypeParameters
Examples of code for this rule with { allowFunctionsWithoutTypeParameters: true }
:
- ❌ Incorrect
- ✅ Correct
function foo<T>(t: T) {
return t;
}
const bar = <T>(t: T) => t;
Open in Playgroundfunction foo<T>(t: T): T {
return t;
}
const bar = <T>(t: T): T => t;
function allowedFunction(x: string) {
return x;
}
const allowedArrow = (x: string) => x;
Open in PlaygroundallowedNames
You may pass function/method names you would like this rule to ignore, like so:
{
"@typescript-eslint/explicit-function-return-type": [
"error",
{
"allowedNames": ["ignoredFunctionName", "ignoredMethodName"]
}
]
}
allowIIFEs
Examples of code for this rule with { allowIIFEs: true }
:
- ❌ Incorrect
- ✅ Correct
var func = () => 'foo';
Open in Playgroundvar foo = (() => 'foo')();
var bar = (function () {
return 'bar';
})();
Open in PlaygroundWhen Not To Use It
If you don't find the added cost of explicitly writing function return types to be worth the visual clarity, or your project is not large enough for it to be a factor in type checking performance, then you will not need this rule.
Further Reading
- TypeScript Functions