Skip to content

Commit

Permalink
feat(linter): support direct const assertions in useExplicitFunctionR…
Browse files Browse the repository at this point in the history
…eturnType rule (#4027)
  • Loading branch information
kaykdm authored Sep 21, 2024
1 parent 29266a0 commit f6e6cb6
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use biome_analyze::{
};
use biome_console::markup;
use biome_js_semantic::HasClosureAstNode;
use biome_js_syntax::AnyJsBinding;
use biome_js_syntax::{AnyJsBinding, AnyJsExpression, AnyJsFunctionBody, AnyTsType};
use biome_js_syntax::{
AnyJsFunction, JsGetterClassMember, JsGetterObjectMember, JsMethodClassMember,
JsMethodObjectMember,
Expand Down Expand Up @@ -61,6 +61,11 @@ declare_lint_rule! {
/// }
/// ```
///
/// ```ts,expect_diagnostic
/// // Should use const assertions
/// const func = (value: number) => ({ type: 'X', value }) as any;
/// ```
///
/// ### Valid
/// ```ts
/// // No return value should be expected (void)
Expand Down Expand Up @@ -90,6 +95,10 @@ declare_lint_rule! {
/// }
/// ```
///
/// ```ts
/// const func = (value: number) => ({ foo: 'bar', value }) as const;
/// ```
///
pub UseExplicitFunctionReturnType {
version: "next",
name: "useExplicitFunctionReturnType",
Expand Down Expand Up @@ -117,6 +126,10 @@ impl Rule for UseExplicitFunctionReturnType {
return None;
}

if is_direct_const_assertion_in_arrow_functions(func) {
return None;
}

let func_range = func.syntax().text_range();
if let Ok(Some(AnyJsBinding::JsIdentifierBinding(id))) = func.id() {
return Some(TextRange::new(
Expand Down Expand Up @@ -176,3 +189,28 @@ impl Rule for UseExplicitFunctionReturnType {
)
}
}

/**
* Checks if an arrow function immediately returns a `as const` value.
* const func = (value: number) => ({ foo: 'bar', value }) as const;
* const func = () => x as const;
*/
fn is_direct_const_assertion_in_arrow_functions(func: &AnyJsFunction) -> bool {
let AnyJsFunction::JsArrowFunctionExpression(arrow_func) = func else {
return false;
};

let Ok(AnyJsFunctionBody::AnyJsExpression(expr)) = arrow_func.body() else {
return false;
};

let AnyJsExpression::TsAsExpression(ts_expr) = expr else {
return false;
};

let Ok(AnyTsType::TsReferenceType(ts_ref)) = ts_expr.ty() else {
return false;
};

ts_ref.text() == "const"
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,6 @@ const obj = {
return "test"
},
};

const func = (value: number) => ({ type: 'X', value }) as any;
const func = (value: number) => ({ type: 'X', value }) as Action;
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ const obj = {
},
};

const func = (value: number) => ({ type: 'X', value }) as any;
const func = (value: number) => ({ type: 'X', value }) as Action;
```

# Diagnostics
Expand Down Expand Up @@ -254,3 +256,37 @@ invalid.ts:37:3 lint/nursery/useExplicitFunctionReturnType ━━━━━━━
```

```
invalid.ts:42:14 lint/nursery/useExplicitFunctionReturnType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! Missing return type on function.
40 │ };
41 │
> 42 │ const func = (value: number) => ({ type: 'X', value }) as any;
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43 │ const func = (value: number) => ({ type: 'X', value }) as Action;
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:43:14 lint/nursery/useExplicitFunctionReturnType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! Missing return type on function.
42 │ const func = (value: number) => ({ type: 'X', value }) as any;
> 43 │ const func = (value: number) => ({ type: 'X', value }) as Action;
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking.
i Add a return type annotation.
```
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,6 @@ const obj = {
return "test"
},
};

const func = (value: number) => ({ foo: 'bar', value }) as const;
const func = () => x as const;
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,6 @@ const obj = {
},
};

const func = (value: number) => ({ foo: 'bar', value }) as const;
const func = () => x as const;
```

0 comments on commit f6e6cb6

Please sign in to comment.