Skip to main content

Summary

Our current linter rules are a bit loose, allowing us to make mistakes like using as any, non-null assertions (shouldntBeNull!), and redundant conditionals (true ? true : false). Although we are careful when reviewing PRs, these things can still slip through. Therefore, we need to introduce a few more rules to make our configuration stricter.

Motivation

To improve code predictability and maintainability using stricter, automated lint rules. This will also make PR reviews more efficient by automatically catching issues like as any, saving developers from repeatedly providing the same feedback manually.

Solution

To achieve the goals, we need some new rules. Warnings will highlight potential issues without blocking commits initially, allowing for gradual adoption.

Accessibility Rules (Making Web Content Usable for Everyone)

  • useSemanticElements (warn)
    • Why: Enforces the use of HTML elements that convey meaning (like <nav>, <article>, <button>) over generic <div> or <span> elements for accessibility and SEO benefits. Screen readers and other assistive technologies rely on semantic markup.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: useSemanticElements
  • useFocusableInteractive (warn)
    • Why: Ensures that interactive elements that are focusable (can receive keyboard focus) are accessible via keyboard navigation. Elements with click handlers should generally be focusable or contained within focusable elements.
    • Problematic Example:
    • Preferred: Use inherently focusable elements like <button> or ensure custom interactive elements have appropriate tabIndex (usually 0) and ARIA roles if needed.
    • Docs: Biome: useFocusableInteractive

Correctness Rules (Avoiding Errors & Improving Reliability)

  • noUnusedVariables (error)
    • Why: Prevents declaring variables that are never used, which clutters the code and can sometimes indicate incomplete logic or typos.
    • Problematic Example:
    • Preferred: Remove the unused variable.
    • Docs: Biome: noUnusedVariables
  • useExhaustiveDependencies (warn)
    • Why: Specifically for React’s Hooks (useEffect, useCallback, etc.), this rule checks that all variables from the surrounding scope used inside the hook are included in the dependency array. Missing dependencies can lead to stale closures and unexpected behavior.
    • Problematic Example:
    • Preferred: Include all dependencies identified by the linter.
    • Docs: Biome: useExhaustiveDependencies
  • noUnusedImports (warn)
    • Why: Flags imported variables, types, or modules that are not used anywhere in the file. This keeps the import list clean and avoids unnecessary dependencies.
    • Problematic Example:
    • Preferred: Remove the unused import.
    • Docs: Biome: noUnusedImports
  • useJsxKeyInIterable (warn)
    • Why: Requires a unique key prop when rendering lists of elements in JSX using iterators like map. React uses these keys to efficiently update the list and maintain component state.
    • Problematic Example:
    • Preferred: Add a unique and stable key to the outermost element returned by the map.
    • Docs: Biome: useJsxKeyInIterable
  • noUnsafeOptionalChaining (warn)
    • Why: Prevents optional chaining (?.) in contexts where it doesn’t provide safety, such as arithmetic operations or assignments, where a null or undefined result would likely cause a runtime error anyway.
    • Problematic Example:
    • Preferred: Use nullish coalescing (??) or explicit checks to handle potential null/undefined before the operation.
    • Docs: Biome: noUnsafeOptionalChaining

Security Rules

  • noDangerouslySetInnerHtml (warn)
    • Why: Prevents the use of dangerouslySetInnerHTML in JSX, which can expose your application to cross-site scripting (XSS) attacks if the injected HTML comes from user input.
    • Problematic Example:
    • Preferred: Use safer methods to render dynamic content, like directly rendering text or using libraries that sanitize HTML.
    • Docs: Biome: noDangerouslySetInnerHtml

Style Rules (Code Consistency & Readability)

  • useConst (warn)
    • Why: Encourages using const for variables that are never reassigned after their initial declaration. This improves readability by signaling the variable’s immutability.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: useConst
  • noNonNullAssertion (warn)
    • Why: Discourages the use of the non-null assertion operator (!), which tells TypeScript a value is not null or undefined without actual checks. Overuse can hide potential runtime errors. This relates to the shouldntBeNull! example mentioned earlier.
    • Problematic Example:
    • Preferred: Use type guards, default values, or optional chaining (user?.name).
    • Docs: Biome: noNonNullAssertion
  • noUselessElse (warn)
    • Why: Prevents else blocks when the if block contains a return, throw, continue, or break statement, making the code less nested and easier to read.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: noUselessElse
  • useImportType (warn)
    • Why: Encourages using import type for importing only types. This clearly signals intent and can sometimes help build tools optimize imports.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: useImportType
  • useFragmentSyntax (warn)
    • Why: Promotes the shorter <> syntax for React Fragments over <React.Fragment>.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: useFragmentSyntax
  • useDefaultSwitchClause (warn)
    • Why: Enforces that switch statements have a default case, preventing potential errors if an unexpected value is encountered.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: useDefaultSwitchClause
  • useAsConstAssertion (warn)
    • Why: Suggests using as const assertions for object and array literals when you want their properties/elements to be treated as specific literal types rather than general types (e.g., string instead of "ACTIVE").
    • Problematic Example:
    • Preferred:
    • Docs: Biome: useAsConstAssertion
  • useTemplate (warn)
    • Why: Prefers template literals (backticks `) over string concatenation (+) for readability when embedding expressions.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: useTemplate
  • useNamingConvention (warn)
    • Why: Enforces consistent naming conventions (e.g., camelCase for variables, PascalCase for classes/types) across the codebase, improving readability. Configuration might be needed to match team style.
    • Problematic Example (depends on config):
    • Preferred (typical JS/TS):
    • Docs: Biome: useNamingConvention
  • noYodaExpression (warn)
    • Why: Prevents “Yoda” conditions where the literal/constant comes before the variable (e.g., if (5 === count)). These can be less intuitive to read.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: noYodaExpression
  • noUnusedTemplateLiteral (warn)
    • Why: Flags template literals that don’t contain any expressions, as regular string literals are simpler.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: noUnusedTemplateLiteral
  • noNegationElse (warn)
    • Why: Suggests refactoring if/else statements where the if condition is negated, often improving readability by handling the positive case first.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: noNegationElse
  • useSelfClosingElements (warn)
    • Why: Requires using self-closing tags for JSX elements with no children.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: useSelfClosingElements
  • useShorthandAssign (warn)
    • Why: Encourages using shorthand assignment operators (+=, -=, *=, etc.) for brevity.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: useShorthandAssign

Suspicious Rules (Potential Logic Errors)

  • noDoubleEquals (warn)
    • Why: Discourages == and != in favor of the type-safe === and !== to avoid unexpected type coercion issues.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: noDoubleEquals
  • useIsArray (warn)
    • Why: Enforces the use of Array.isArray() to check for arrays instead of instanceof Array, which can fail across different JavaScript execution contexts (e.g., iframes).
    • Problematic Example:
    • Preferred:
    • Docs: Biome: useIsArray
  • useAwait (warn)
    • Why: Flags async functions that don’t use await, as the async keyword might be unnecessary or indicate a missed await.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: useAwait
  • noFallthroughSwitchClause (warn)
    • Why: Prevents accidental fall-through in switch statements by requiring break, return, throw, or continue at the end of non-empty case blocks (unless explicitly commented // biome-ignore lint/suspicious/noFallthroughSwitchClause: <explanation>).
    • Problematic Example:
    • Preferred:
    • Docs: Biome: noFallthroughSwitchClause
  • noExplicitAny (warn)
    • Why: Discourages the explicit use of any as a type, as it effectively disables TypeScript’s type checking for that variable. This relates to the as any example mentioned earlier.
    • Problematic Example:
    • Preferred: Use specific types, generics, or unknown (which requires type checking before use).
    • Docs: Biome: noExplicitAny
  • noConsoleLog (warn)
    • Why: Flags console.log (and other console methods) to prevent debug statements from being accidentally committed to production code. Consider using a dedicated logger or removing logs before merging.
    • Problematic Example:
    • Preferred: Remove the log or use a proper logging library.
    • Docs: Biome: noConsoleLog

Complexity Rules (Simplifying Code)

  • noUselessTernary (warn)
    • Why: Prevents ternary operators that directly return boolean literals (true/false) based on a condition, as the condition itself can be used. This relates to the true ? true : false example.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: noUselessTernary
  • noUselessTypeConstraint (warn)
    • Why: Flags redundant type constraints in generics like T extends any or T extends unknown, which provide no additional limitation.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: noUselessTypeConstraint
  • useSimplifiedLogicExpression (warn)
    • Why: Encourages simplifying boolean expressions, such as removing double negations (!!).
    • Problematic Example:
    • Preferred:
    • Docs: Biome: useSimplifiedLogicExpression
  • noUselessStringConcat (warn)
    • Why: Prevents concatenating two string literals, which should just be combined into a single literal.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: noUselessStringConcat
  • useOptionalChain (warn)
    • Why: Promotes using the optional chaining operator (?.) instead of longer logical AND (&&) chains for accessing nested properties safely.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: useOptionalChain
  • useDateNow (warn)
    • Why: Suggests using Date.now() which is slightly more performant and concise than new Date().getTime() or +new Date() for getting a timestamp.
    • Problematic Example:
    • Preferred:
    • Docs: Biome: useDateNow
  • noExtraBooleanCast (warn)
    • Why: Prevents unnecessary boolean casts (using Boolean() or !!) in contexts where the value is already treated as a boolean (like if statements or logical operators).
    • Problematic Example:
    • Preferred:
    • Docs: Biome: noExtraBooleanCast

By enabling these rules, we aim to catch more potential errors and enforce stylistic consistency automatically.