Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(linter): implement useExplicitFunctionReturnType #3990

Merged
merged 14 commits into from
Sep 20, 2024

Conversation

kaykdm
Copy link
Contributor

@kaykdm kaykdm commented Sep 19, 2024

Summary

Related issue: #2017

This PR introduces the @typescript-eslint/explicit-function-return-type rule to Biome. Currently, it only enforces the basic cases without any additional options configured.

In future PRs, I will implement each option for this rule separately. Due to the complexity of the implementation, handling each option individually will allow for thorough testing and easier review.

original implementation

Todos

I will implement each option for this rule separately in different PRs

  • Implement allowExpressions option
  • Implement allowTypedFunctionExpression soption
  • Implement allowHigherOrderFunctions option
  • Implement allowDirectConstAssertionInArrowFunctions option
  • Implement allowConciseArrowFunctionExpressionsStartingWithVoid option
  • Implement allowFunctionsWithoutTypeParameters option
  • Implement allowedNames option
  • Implement allowIIFEs option

@github-actions github-actions bot added A-Project Area: project A-Linter Area: linter L-JavaScript Language: JavaScript and super languages A-Diagnostic Area: diagnostocis labels Sep 19, 2024
Comment on lines 2 to 22
function test(): void {
return;
}

var fn = function (): number {
return 1;
};

var arrowFn = (): string => 'test';

class Test {
constructor() {}
get prop(): number {
return 1;
}
set prop() {}
method(): void {
return;
}
arrow = (): string => 'arrow';
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +1 to +28
function test(a: number, b: number) {
return;
}

function test() {
return;
}

var fn = function () {
return 1;
};

var arrowFn = () => "test";

class Test {
constructor() {}
get prop() {
return 1;
}
set prop() {}
method() {
return;
}
arrow = () => "arrow";
private method() {
return;
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

@arendjr arendjr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love to have this rule!

/// 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be nice to add that explicit return types also reduce the chance of bugs by asserting the return type and it avoids surprising "action at a distance", where changing the body of one function may cause failures inside another function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion! I've added that point to the description!

/// return;
/// }
/// }
/// ```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about a function without any explicit return statement? Is the type annotation required there too? If not, might be good to point out in the examples.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about a function without any explicit return statement? Is the type annotation required there too?

Yes it is required, but I think it's nice to include it in the example. I added it to the invalid example!

Copy link

codspeed-hq bot commented Sep 19, 2024

CodSpeed Performance Report

Merging #3990 will degrade performances by 6.5%

Comparing kaykdm:use-explicit-function-return-type (b7a1fe4) with main (d137533)

Summary

⚡ 1 improvements
❌ 1 regressions
✅ 105 untouched benchmarks

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Benchmarks breakdown

Benchmark main kaykdm:use-explicit-function-return-type Change
js_analyzer[lint_13640784270757307929.ts] 30.2 ms 32.3 ms -6.5%
react.production.min_3378072959512366797.js[uncached] 2.2 ms 2.1 ms +6.12%

@github-actions github-actions bot added the A-CLI Area: CLI label Sep 20, 2024
@arendjr
Copy link
Contributor

arendjr commented Sep 20, 2024

Great stuff! Do you want to create a CHANGELOG entry?

@Conaclos
Copy link
Member

Hi! Thanks for the good stuff!

In future PRs, I will implement each option for this rule separately. Due to the complexity of the implementation, handling each option individually will allow for thorough testing and easier review.

We usually refrain from implementing a rule's options unless they are widely used in the community. The number of options provided by explicit-function-return-type looks like a code smell to me.

Taking a look at GitHub Code search:

  • explicit-function-return-type is used 74k times
  • allowConciseArrowFunctionExpressionsStartingWithVoid is used 800 times
  • allowDirectConstAssertionInArrowFunctions is used 600 times
  • allowFunctionsWithoutTypeParameters is used 50 times
  • allowHigherOrderFunctions is used [1.6k times](path:eslint "explicit-function-return-type" allowHigherOrderFunctions)
  • allowIIFEs is used 90 times
  • allowTypedFunctionExpressions is used 2.8k times
  • allowedNames is used 750 times
  • allowExpressions is used 10k times

Without taking account that some of these occurrences actually set the default value...
Only allowExpressions seems widely used. We could skip its implementation and diverge from ESLint by allowing callbacks without return types by default.

Moreover, I would like that useExplicitFunctionReturnType be compatible with the new isolated declaration mode of TypeScript. Some options can conflict with this mode.

Thus, I think we should not implement any option for this rule.
Note that we should still accept:

  • Higher order function without return type (ESLint default behavior) - We could restrict our implementation to arrow function.
  • Typed function expression (ESLint default behavior)
  • Direct const assertion in arrow function (ESLint default behavior)
  • Callbacks without return types (ESLint allowExpressions)

@kaykdm
Copy link
Contributor Author

kaykdm commented Sep 20, 2024

Thus, I think we should not implement any option for this rule.
Note that we should still accept:

Higher order function without return type (ESLint default behavior) - We could restrict our implementation to arrow function.
Typed function expression (ESLint default behavior)
Direct const assertion in arrow function (ESLint default behavior)
Callbacks without return types (ESLint allowExpressions)

I totally agree with this. I implemented the same rule in Oxc Linter, but it was quite painful and I ran into some issues. That being said, I’m happy to work on these options you mentioned in separate PRs.

Copy link
Member

@Conaclos Conaclos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! LGTM :)

@Conaclos Conaclos merged commit b76cb41 into biomejs:main Sep 20, 2024
11 of 12 checks passed
@kaykdm kaykdm deleted the use-explicit-function-return-type branch September 21, 2024 01:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-CLI Area: CLI A-Diagnostic Area: diagnostocis A-Linter Area: linter A-Project Area: project L-JavaScript Language: JavaScript and super languages
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants