From dd41388d38c470740146725e395bafcd98d89fba Mon Sep 17 00:00:00 2001 From: kaykdm Date: Sun, 29 Sep 2024 20:53:13 +0900 Subject: [PATCH 1/2] feat(linter): support higher-order function detection (excluding nested statements) in useExplicitFunctionReturnType --- .../use_explicit_function_return_type.rs | 88 +++++++++- .../useExplicitFunctionReturnType/invalid.ts | 39 ++++- .../invalid.ts.snap | 165 ++++++++++++++++++ .../useExplicitFunctionReturnType/valid.ts | 16 +- .../valid.ts.snap | 14 ++ 5 files changed, 319 insertions(+), 3 deletions(-) diff --git a/crates/biome_js_analyze/src/lint/nursery/use_explicit_function_return_type.rs b/crates/biome_js_analyze/src/lint/nursery/use_explicit_function_return_type.rs index 469aa72d34b6..b69a99911b71 100644 --- a/crates/biome_js_analyze/src/lint/nursery/use_explicit_function_return_type.rs +++ b/crates/biome_js_analyze/src/lint/nursery/use_explicit_function_return_type.rs @@ -4,7 +4,8 @@ use biome_analyze::{ use biome_console::markup; use biome_js_semantic::HasClosureAstNode; use biome_js_syntax::{ - AnyJsBinding, AnyJsExpression, AnyJsFunctionBody, AnyTsType, JsFileSource, JsSyntaxKind, + AnyJsBinding, AnyJsExpression, AnyJsFunctionBody, AnyJsStatement, AnyTsType, JsFileSource, + JsStatementList, JsSyntaxKind, }; use biome_js_syntax::{ AnyJsFunction, JsGetterClassMember, JsGetterObjectMember, JsMethodClassMember, @@ -68,6 +69,16 @@ declare_lint_rule! { /// const func = (value: number) => ({ type: 'X', value }) as any; /// ``` /// + /// ```ts,expect_diagnostic + /// const arrowFn = () => () => {}; + /// ``` + /// + /// ```ts,expect_diagnostic + /// const arrowFn = () => { + /// return () => { }; + /// } + /// ``` + /// /// ### Valid /// ```ts /// // No return value should be expected (void) @@ -110,6 +121,15 @@ declare_lint_rule! { /// (() => {})(); /// ``` /// + /// ```ts + /// const arrowFn = () => (): void => {}; + /// ``` + /// + /// ```ts + /// const arrowFn = () => { + /// return (): void => { }; + /// } + /// pub UseExplicitFunctionReturnType { version: "next", name: "useExplicitFunctionReturnType", @@ -150,6 +170,10 @@ impl Rule for UseExplicitFunctionReturnType { return None; } + if is_higher_order_function(func) { + return None; + } + let func_range = func.syntax().text_range(); if let Ok(Some(AnyJsBinding::JsIdentifierBinding(id))) = func.id() { return Some(TextRange::new( @@ -266,3 +290,65 @@ fn is_function_used_in_argument_or_expression_list(func: &AnyJsFunction) -> bool ) ) } + +/// Checks whether the given function is a higher-order function, i.e., a function +/// that returns another function either directly in its body or as an expression. +/// +/// A higher-order function is one that returns either a regular function or an arrow +/// function from within its body. +/// +/// # Arguments +/// +/// * `func` - A reference to an `AnyJsFunction` that represents the JavaScript function to inspect. +/// +/// # Returns +/// +/// * `true` if the function returns another function (either a regular function or an arrow function). +/// * `false` if it does not return a function or if the body is not a valid returnable function expression. +/// +/// # Note +/// +/// This function currently **does not support** detecting a return of a function +/// inside other statements like `if` statements or `switch` statements. It only detects +/// direct returns of functions or function returns in a straightforward function body. +fn is_higher_order_function(func: &AnyJsFunction) -> bool { + match func.body().ok() { + Some(AnyJsFunctionBody::AnyJsExpression(expr)) => { + matches!( + expr, + AnyJsExpression::JsArrowFunctionExpression(_) + | AnyJsExpression::JsFunctionExpression(_) + ) + } + Some(AnyJsFunctionBody::JsFunctionBody(func_body)) => { + check_statements_for_function_return(func_body.statements()) + } + _ => false, + } +} + +/// Checks whether the given list of JavaScript statements contains a return statement +/// that returns a function expression (either a regular function or an arrow function). +/// +/// # Arguments +/// +/// * `statements` - A list of JavaScript statements (`JsStatementList`) to inspect. +/// +/// # Returns +/// +/// * `true` if the list contains a return statement with a function expression as its argument. +/// * `false` if no such return statement is found or if the list is empty. +fn check_statements_for_function_return(statements: JsStatementList) -> bool { + statements.into_iter().any(|statement| { + if let AnyJsStatement::JsReturnStatement(return_stmt) = statement { + if let Some(args) = return_stmt.argument() { + return matches!( + args, + AnyJsExpression::JsFunctionExpression(_) + | AnyJsExpression::JsArrowFunctionExpression(_) + ); + } + } + false + }) +} diff --git a/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/invalid.ts b/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/invalid.ts index 290a11b5e955..e82707d1cee0 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/invalid.ts +++ b/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/invalid.ts @@ -43,4 +43,41 @@ const func = (value: number) => ({ type: 'X', value }) as any; const func = (value: number) => ({ type: 'X', value }) as Action; export default () => {}; -export default function () {} \ No newline at end of file +export default function () {} + +// check higher order functions +const arrowFn = () => () => {}; +const arrowFn = () => function() {} +function fn() { + let str = "hey"; + return function () { + return str; + }; +} +const arrowFn = () => { + return () => { }; +} + +// does not support detecting a return of a function inside other statements like if, switch, etc. +const arrowFn = (a: number) => { + if (a === 1) { + return (): void => { }; + } else { + return (): number => { + return a + 2 + } + } +} +const arrowFn = (a: number) => { + switch (a) { + case 1: { + return (): void => { }; + } + case 2: { + return (): void => { }; + } + default: { + return (): void => { }; + } + } +} \ No newline at end of file diff --git a/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/invalid.ts.snap b/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/invalid.ts.snap index 3d5794922220..25f77074123d 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/invalid.ts.snap +++ b/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/invalid.ts.snap @@ -50,6 +50,43 @@ const func = (value: number) => ({ type: 'X', value }) as Action; export default () => {}; export default function () {} + +// check higher order functions +const arrowFn = () => () => {}; +const arrowFn = () => function() {} +function fn() { + let str = "hey"; + return function () { + return str; + }; +} +const arrowFn = () => { + return () => { }; +} + +// does not support detecting a return of a function inside other statements like if, switch, etc. +const arrowFn = (a: number) => { + if (a === 1) { + return (): void => { }; + } else { + return (): number => { + return a + 2 + } + } +} +const arrowFn = (a: number) => { + switch (a) { + case 1: { + return (): void => { }; + } + case 2: { + return (): void => { }; + } + default: { + return (): void => { }; + } + } +} ``` # Diagnostics @@ -307,6 +344,7 @@ invalid.ts:45:16 lint/nursery/useExplicitFunctionReturnType ━━━━━━ > 45 │ export default () => {}; │ ^^^^^^^^ 46 │ export default function () {} + 47 │ i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. @@ -323,6 +361,133 @@ invalid.ts:46:16 lint/nursery/useExplicitFunctionReturnType ━━━━━━ 45 │ export default () => {}; > 46 │ export default function () {} │ ^^^^^^^^^^^^^^ + 47 │ + 48 │ // check higher order functions + + i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. + + i Add a return type annotation. + + +``` + +``` +invalid.ts:49:23 lint/nursery/useExplicitFunctionReturnType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Missing return type on function. + + 48 │ // check higher order functions + > 49 │ const arrowFn = () => () => {}; + │ ^^^^^^^^ + 50 │ const arrowFn = () => function() {} + 51 │ function fn() { + + i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. + + i Add a return type annotation. + + +``` + +``` +invalid.ts:50:23 lint/nursery/useExplicitFunctionReturnType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Missing return type on function. + + 48 │ // check higher order functions + 49 │ const arrowFn = () => () => {}; + > 50 │ const arrowFn = () => function() {} + │ ^^^^^^^^^^^^^ + 51 │ function fn() { + 52 │ let str = "hey"; + + i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. + + i Add a return type annotation. + + +``` + +``` +invalid.ts:53:10 lint/nursery/useExplicitFunctionReturnType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Missing return type on function. + + 51 │ function fn() { + 52 │ let str = "hey"; + > 53 │ return function () { + │ ^^^^^^^^^^^^^ + > 54 │ return str; + > 55 │ }; + │ ^ + 56 │ } + 57 │ const arrowFn = () => { + + i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. + + i Add a return type annotation. + + +``` + +``` +invalid.ts:58:10 lint/nursery/useExplicitFunctionReturnType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Missing return type on function. + + 56 │ } + 57 │ const arrowFn = () => { + > 58 │ return () => { }; + │ ^^^^^^^^^ + 59 │ } + 60 │ + + i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. + + i Add a return type annotation. + + +``` + +``` +invalid.ts:62:17 lint/nursery/useExplicitFunctionReturnType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Missing return type on function. + + 61 │ // does not support detecting a return of a function inside other statements like if, switch, etc. + > 62 │ const arrowFn = (a: number) => { + │ ^^^^^^^^^^^^^^^^ + > 63 │ if (a === 1) { + ... + > 69 │ } + > 70 │ } + │ ^ + 71 │ const arrowFn = (a: number) => { + 72 │ switch (a) { + + i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. + + i Add a return type annotation. + + +``` + +``` +invalid.ts:71:17 lint/nursery/useExplicitFunctionReturnType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Missing return type on function. + + 69 │ } + 70 │ } + > 71 │ const arrowFn = (a: number) => { + │ ^^^^^^^^^^^^^^^^ + > 72 │ switch (a) { + ... + > 80 │ return (): void => { }; + > 81 │ } + > 82 │ } + > 83 │ } + │ ^ i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. diff --git a/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/valid.ts b/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/valid.ts index aa6e78b37dc6..c91b63d2ab13 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/valid.ts +++ b/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/valid.ts @@ -54,4 +54,18 @@ fn(function () {}); (() => { console.log("This is an IIFE"); })(); -setTimeout(function() { console.log("Hello!"); }, 1000); \ No newline at end of file +setTimeout(function() { console.log("Hello!"); }, 1000); + + +// check higher order functions +const arrowFn = () => (): void => {}; +const arrowFn = () => function(): void {} +function fn() { + let str = "hey"; + return function (): string { + return str; + }; +} +const arrowFn = () => { + return (): void => { }; +} \ No newline at end of file diff --git a/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/valid.ts.snap b/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/valid.ts.snap index 23bdedafbf97..394403c460ee 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/valid.ts.snap +++ b/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/valid.ts.snap @@ -61,4 +61,18 @@ fn(function () {}); console.log("This is an IIFE"); })(); setTimeout(function() { console.log("Hello!"); }, 1000); + + +// check higher order functions +const arrowFn = () => (): void => {}; +const arrowFn = () => function(): void {} +function fn() { + let str = "hey"; + return function (): string { + return str; + }; +} +const arrowFn = () => { + return (): void => { }; +} ``` From ed3ec3040e59a81306cdb74120ae14256bb2cd65 Mon Sep 17 00:00:00 2001 From: kaykdm Date: Mon, 30 Sep 2024 22:38:35 +0900 Subject: [PATCH 2/2] Refactor and rename check_statements_for_function_return to is_first_statement_function_return --- .../use_explicit_function_return_type.rs | 78 ++++++++--- .../useExplicitFunctionReturnType/invalid.ts | 21 ++- .../invalid.ts.snap | 124 +++++++++++------- .../useExplicitFunctionReturnType/valid.ts | 6 - .../valid.ts.snap | 6 - 5 files changed, 152 insertions(+), 83 deletions(-) diff --git a/crates/biome_js_analyze/src/lint/nursery/use_explicit_function_return_type.rs b/crates/biome_js_analyze/src/lint/nursery/use_explicit_function_return_type.rs index b69a99911b71..788378c6cd24 100644 --- a/crates/biome_js_analyze/src/lint/nursery/use_explicit_function_return_type.rs +++ b/crates/biome_js_analyze/src/lint/nursery/use_explicit_function_return_type.rs @@ -69,6 +69,8 @@ declare_lint_rule! { /// const func = (value: number) => ({ type: 'X', value }) as any; /// ``` /// + /// The following pattern is considered incorrect code for a higher-order function, as the returned function does not specify a return type: + /// /// ```ts,expect_diagnostic /// const arrowFn = () => () => {}; /// ``` @@ -79,6 +81,28 @@ declare_lint_rule! { /// } /// ``` /// + /// The following pattern is considered incorrect code for a higher-order function because the function body contains multiple statements. We only check whether the first statement is a function return. + /// + /// ```ts,expect_diagnostic + /// // A function has multiple statements in the body + /// function f() { + /// if (x) { + /// return 0; + /// } + /// return (): void => {} + /// } + /// ``` + /// + /// ```ts,expect_diagnostic + /// // A function has multiple statements in the body + /// function f() { + /// let str = "test"; + /// return (): string => { + /// str; + /// } + /// } + /// ``` + /// /// ### Valid /// ```ts /// // No return value should be expected (void) @@ -108,10 +132,14 @@ declare_lint_rule! { /// } /// ``` /// + /// The following patterns are considered correct code for a function immediately returning a value with `as const`: + /// /// ```ts /// const func = (value: number) => ({ foo: 'bar', value }) as const; /// ``` /// + /// The following patterns are considered correct code for a function allowed within specific expression contexts, such as an IIFE, a function passed as an argument, or a function inside an array: + /// /// ```ts /// // Callbacks without return types /// setTimeout(function() { console.log("Hello!"); }, 1000); @@ -122,13 +150,23 @@ declare_lint_rule! { /// ``` /// /// ```ts + /// // a function inside an array + /// [function () {}, () => {}]; + /// ``` + /// + /// The following pattern is considered correct code for a higher-order function, where the returned function explicitly specifies a return type and the function body contains only one statement: + /// + /// ```ts + /// // the outer function returns an inner function that has a `void` return type /// const arrowFn = () => (): void => {}; /// ``` /// /// ```ts + /// // the outer function returns an inner function that has a `void` return type /// const arrowFn = () => { /// return (): void => { }; /// } + /// ``` /// pub UseExplicitFunctionReturnType { version: "next", @@ -294,9 +332,6 @@ fn is_function_used_in_argument_or_expression_list(func: &AnyJsFunction) -> bool /// Checks whether the given function is a higher-order function, i.e., a function /// that returns another function either directly in its body or as an expression. /// -/// A higher-order function is one that returns either a regular function or an arrow -/// function from within its body. -/// /// # Arguments /// /// * `func` - A reference to an `AnyJsFunction` that represents the JavaScript function to inspect. @@ -309,8 +344,8 @@ fn is_function_used_in_argument_or_expression_list(func: &AnyJsFunction) -> bool /// # Note /// /// This function currently **does not support** detecting a return of a function -/// inside other statements like `if` statements or `switch` statements. It only detects -/// direct returns of functions or function returns in a straightforward function body. +/// inside other statements, such as `if` statements or `switch` statements. It only checks +/// whether the first statement is a return of a function in a straightforward function body. fn is_higher_order_function(func: &AnyJsFunction) -> bool { match func.body().ok() { Some(AnyJsFunctionBody::AnyJsExpression(expr)) => { @@ -321,13 +356,13 @@ fn is_higher_order_function(func: &AnyJsFunction) -> bool { ) } Some(AnyJsFunctionBody::JsFunctionBody(func_body)) => { - check_statements_for_function_return(func_body.statements()) + is_first_statement_function_return(func_body.statements()) } _ => false, } } -/// Checks whether the given list of JavaScript statements contains a return statement +/// Checks whether the first statement in the given list of JavaScript statements is a return statement /// that returns a function expression (either a regular function or an arrow function). /// /// # Arguments @@ -338,17 +373,22 @@ fn is_higher_order_function(func: &AnyJsFunction) -> bool { /// /// * `true` if the list contains a return statement with a function expression as its argument. /// * `false` if no such return statement is found or if the list is empty. -fn check_statements_for_function_return(statements: JsStatementList) -> bool { - statements.into_iter().any(|statement| { - if let AnyJsStatement::JsReturnStatement(return_stmt) = statement { - if let Some(args) = return_stmt.argument() { - return matches!( - args, - AnyJsExpression::JsFunctionExpression(_) - | AnyJsExpression::JsArrowFunctionExpression(_) - ); +fn is_first_statement_function_return(statements: JsStatementList) -> bool { + statements + .into_iter() + .next() + .and_then(|stmt| { + if let AnyJsStatement::JsReturnStatement(return_stmt) = stmt { + return_stmt.argument() + } else { + None } - } - false - }) + }) + .map_or(false, |args| { + matches!( + args, + AnyJsExpression::JsFunctionExpression(_) + | AnyJsExpression::JsArrowFunctionExpression(_) + ) + }) } diff --git a/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/invalid.ts b/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/invalid.ts index e82707d1cee0..16fe67e58b09 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/invalid.ts +++ b/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/invalid.ts @@ -48,17 +48,12 @@ export default function () {} // check higher order functions const arrowFn = () => () => {}; const arrowFn = () => function() {} -function fn() { - let str = "hey"; - return function () { - return str; - }; -} const arrowFn = () => { return () => { }; } // does not support detecting a return of a function inside other statements like if, switch, etc. +// we check only the first statment const arrowFn = (a: number) => { if (a === 1) { return (): void => { }; @@ -80,4 +75,18 @@ const arrowFn = (a: number) => { return (): void => { }; } } +} + +function f() { + if (x) { + return 0; + } + return (): void => {} +} + +function fn() { + let str = "hey"; + return function (): string { + return str; + }; } \ No newline at end of file diff --git a/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/invalid.ts.snap b/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/invalid.ts.snap index 25f77074123d..9b84cc810709 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/invalid.ts.snap +++ b/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/invalid.ts.snap @@ -54,17 +54,12 @@ export default function () {} // check higher order functions const arrowFn = () => () => {}; const arrowFn = () => function() {} -function fn() { - let str = "hey"; - return function () { - return str; - }; -} const arrowFn = () => { return () => { }; } // does not support detecting a return of a function inside other statements like if, switch, etc. +// we check only the first statment const arrowFn = (a: number) => { if (a === 1) { return (): void => { }; @@ -87,6 +82,20 @@ const arrowFn = (a: number) => { } } } + +function f() { + if (x) { + return 0; + } + return (): void => {} +} + +function fn() { + let str = "hey"; + return function (): string { + return str; + }; +} ``` # Diagnostics @@ -380,7 +389,7 @@ invalid.ts:49:23 lint/nursery/useExplicitFunctionReturnType ━━━━━━ > 49 │ const arrowFn = () => () => {}; │ ^^^^^^^^ 50 │ const arrowFn = () => function() {} - 51 │ function fn() { + 51 │ const arrowFn = () => { i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. @@ -398,8 +407,8 @@ invalid.ts:50:23 lint/nursery/useExplicitFunctionReturnType ━━━━━━ 49 │ const arrowFn = () => () => {}; > 50 │ const arrowFn = () => function() {} │ ^^^^^^^^^^^^^ - 51 │ function fn() { - 52 │ let str = "hey"; + 51 │ const arrowFn = () => { + 52 │ return () => { }; i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. @@ -409,19 +418,16 @@ invalid.ts:50:23 lint/nursery/useExplicitFunctionReturnType ━━━━━━ ``` ``` -invalid.ts:53:10 lint/nursery/useExplicitFunctionReturnType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.ts:52:10 lint/nursery/useExplicitFunctionReturnType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Missing return type on function. - 51 │ function fn() { - 52 │ let str = "hey"; - > 53 │ return function () { - │ ^^^^^^^^^^^^^ - > 54 │ return str; - > 55 │ }; - │ ^ - 56 │ } - 57 │ const arrowFn = () => { + 50 │ const arrowFn = () => function() {} + 51 │ const arrowFn = () => { + > 52 │ return () => { }; + │ ^^^^^^^^^ + 53 │ } + 54 │ i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. @@ -431,16 +437,21 @@ invalid.ts:53:10 lint/nursery/useExplicitFunctionReturnType ━━━━━━ ``` ``` -invalid.ts:58:10 lint/nursery/useExplicitFunctionReturnType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.ts:57:17 lint/nursery/useExplicitFunctionReturnType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Missing return type on function. - 56 │ } - 57 │ const arrowFn = () => { - > 58 │ return () => { }; - │ ^^^^^^^^^ - 59 │ } - 60 │ + 55 │ // does not support detecting a return of a function inside other statements like if, switch, etc. + 56 │ // we check only the first statment· + > 57 │ const arrowFn = (a: number) => { + │ ^^^^^^^^^^^^^^^^ + > 58 │ if (a === 1) { + ... + > 64 │ } + > 65 │ } + │ ^ + 66 │ const arrowFn = (a: number) => { + 67 │ switch (a) { i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. @@ -450,20 +461,21 @@ invalid.ts:58:10 lint/nursery/useExplicitFunctionReturnType ━━━━━━ ``` ``` -invalid.ts:62:17 lint/nursery/useExplicitFunctionReturnType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.ts:66:17 lint/nursery/useExplicitFunctionReturnType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Missing return type on function. - 61 │ // does not support detecting a return of a function inside other statements like if, switch, etc. - > 62 │ const arrowFn = (a: number) => { + 64 │ } + 65 │ } + > 66 │ const arrowFn = (a: number) => { │ ^^^^^^^^^^^^^^^^ - > 63 │ if (a === 1) { + > 67 │ switch (a) { ... - > 69 │ } - > 70 │ } + > 77 │ } + > 78 │ } │ ^ - 71 │ const arrowFn = (a: number) => { - 72 │ switch (a) { + 79 │ + 80 │ function f() { i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. @@ -473,21 +485,41 @@ invalid.ts:62:17 lint/nursery/useExplicitFunctionReturnType ━━━━━━ ``` ``` -invalid.ts:71:17 lint/nursery/useExplicitFunctionReturnType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.ts:78:2 lint/nursery/useExplicitFunctionReturnType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Missing return type on function. - 69 │ } - 70 │ } - > 71 │ const arrowFn = (a: number) => { - │ ^^^^^^^^^^^^^^^^ - > 72 │ switch (a) { - ... - > 80 │ return (): void => { }; - > 81 │ } - > 82 │ } - > 83 │ } - │ ^ + 76 │ } + 77 │ } + > 78 │ } + │ + > 79 │ + > 80 │ function f() { + │ ^^^^^^^^^^ + 81 │ if (x) { + 82 │ return 0; + + i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. + + i Add a return type annotation. + + +``` + +``` +invalid.ts:85:2 lint/nursery/useExplicitFunctionReturnType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Missing return type on function. + + 83 │ } + 84 │ return (): void => {} + > 85 │ } + │ + > 86 │ + > 87 │ function fn() { + │ ^^^^^^^^^^^ + 88 │ let str = "hey"; + 89 │ return function (): string { i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. diff --git a/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/valid.ts b/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/valid.ts index c91b63d2ab13..0c381b08a967 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/valid.ts +++ b/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/valid.ts @@ -60,12 +60,6 @@ setTimeout(function() { console.log("Hello!"); }, 1000); // check higher order functions const arrowFn = () => (): void => {}; const arrowFn = () => function(): void {} -function fn() { - let str = "hey"; - return function (): string { - return str; - }; -} const arrowFn = () => { return (): void => { }; } \ No newline at end of file diff --git a/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/valid.ts.snap b/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/valid.ts.snap index 394403c460ee..80b8221a7297 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/valid.ts.snap +++ b/crates/biome_js_analyze/tests/specs/nursery/useExplicitFunctionReturnType/valid.ts.snap @@ -66,12 +66,6 @@ setTimeout(function() { console.log("Hello!"); }, 1000); // check higher order functions const arrowFn = () => (): void => {}; const arrowFn = () => function(): void {} -function fn() { - let str = "hey"; - return function (): string { - return str; - }; -} const arrowFn = () => { return (): void => { }; }