Search code examples
typescript-eslint

@typescript-eslint/explicit-function-return-type allowHigherOrderFunctions exception returns error with the same args


Here's the relevant snippet of my .eslintrc.json:

"rules": {
     "@typescript-eslint/explicit-function-return-type": [
      "warn",
      {
        "allowHigherOrderFunctions": true
      }
    ],
}

With this config I am encountering the following:

// ❌ fails 
const arrowFn1 = (): void => {
  return;
};
export const arrowHoc = () => arrowFn1;

// ✅ passes
export const arrowFn2 = () => (): void => {
  return;
};

I thought the top example would work. Is this expected? Thanks for any input!


Solution

  • This is expected - the lint rule purposely does not track references to understand what variables might be. The point of the rule is to enforce that you're defining strict contracts in your code - which means declaring return types with the declaration.

    () => (): void => { ... } is ignored with the option because the return type is trivially inferred from the declaration in code, without any IDE features - it's trivially read as "a function that returns a function that returns void"
    However with () => variable there isn't the same assurance - instead reading the code you read "a function that returns a variable" - which isn't a strict contract at all!

    One could argue that the rule should ignore it because the variable is defined on the preceding line, however the rule takes a clean, consistent approach as opposed to a messy, confusing one based on lots of exceptions. For example imagine instead if your code was

    import { arrowFn1 } from 'module';
    export const arrowHoc = () => arrowFn1;
    

    What's the return type of arrowHoc? Well to figure that out first you'll need to inspect the exports of module to determine the type of arrowFn1, then you can know the type of arrowHoc.

    If you use variables for indirection, you need to maintain a separate, strict contract for your HOC.