Skip to content

feat(lint): add nursery rule noUnsafeAssignment#9046

Open
sargunv wants to merge 3 commits intobiomejs:mainfrom
sargunv:claude/add-unsafe-type-rules-PuqfR
Open

feat(lint): add nursery rule noUnsafeAssignment#9046
sargunv wants to merge 3 commits intobiomejs:mainfrom
sargunv:claude/add-unsafe-type-rules-PuqfR

Conversation

@sargunv
Copy link

@sargunv sargunv commented Feb 12, 2026

AI disclosure: I used Opus 4.6 with Claude Code to produce this PR. I've made the Claude session public, if you'd like to inspect it. The PR description was written by me. Any discussion on the PR will be replied to by me, not AI.

Summary

This PR adds a new nursery rule noUnsafeAssignment that detects when a value typed as any is assigned to a variable, preventing any from silently spreading through the codebase.

The rule is inspired by typescript-eslint's no-unsafe-assignment rule. It flags cases where:

  • A function returning any is assigned to an unannotated variable
  • A function returning any is assigned to a variable with a non-any/unknown annotation

The rule allows assignments when the variable is explicitly annotated as any or unknown, since the developer has intentionally opted into those types.

Relevant rule request: #7587

If this is merged, I'd be happy to work on porting the other no-unsafe-* too.

Test Plan

The implementation includes test cases:

  • Invalid cases: Assigning any-typed values to unannotated variables and variables with non-any annotations
  • Valid cases: Normal assignments without any, explicit any/unknown annotations, variables without initializers, and unresolved types

@changeset-bot
Copy link

changeset-bot bot commented Feb 12, 2026

🦋 Changeset detected

Latest commit: 37979dc

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@biomejs/biome Patch
@biomejs/cli-win32-x64 Patch
@biomejs/cli-win32-arm64 Patch
@biomejs/cli-darwin-x64 Patch
@biomejs/cli-darwin-arm64 Patch
@biomejs/cli-linux-x64 Patch
@biomejs/cli-linux-arm64 Patch
@biomejs/cli-linux-x64-musl Patch
@biomejs/cli-linux-arm64-musl Patch
@biomejs/wasm-web Patch
@biomejs/wasm-bundler Patch
@biomejs/wasm-nodejs Patch
@biomejs/backend-jsonrpc Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added A-CLI Area: CLI A-Project Area: project A-Linter Area: linter L-JavaScript Language: JavaScript and super languages A-Diagnostic Area: diagnostocis labels Feb 12, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

Walkthrough

Adds a new TypeScript nursery lint rule noUnsafeAssignment to the Biome linter. The rule flags assignments whose initializer’s inferred type is any unless the variable has an explicit any or unknown annotation. Includes rule implementation, a helper to detect explicit annotations, rule options type, tests (valid/invalid) and a changeset entry documenting the addition.

Suggested reviewers

  • ematipico
  • dyc3
  • Netail
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: adding a new nursery lint rule called noUnsafeAssignment.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main
Description check ✅ Passed The description is directly related to the changeset, detailing the new noUnsafeAssignment rule, its purpose, inspiration, and test coverage.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.changeset/add-no-unsafe-assignment-rule.md:
- Around line 1-3: The changeset currently declares the release type as "minor"
for the "@biomejs/biome" entry; change that declaration to "patch" so the
nursery rule targets the main branch instead of being treated as a feature for
next. Locate the changeset header containing the string '"@biomejs/biome":
minor' and update it to '"@biomejs/biome": patch', keeping the rest of the
changeset content intact.
🧹 Nitpick comments (2)
crates/biome_js_analyze/src/lint/nursery/no_unsafe_assignment.rs (1)

105-122: Consider narrowing the diagnostic range to just the expression.

Currently initializer.range() covers = getPayload() including the = token. Using expression.range() instead would point directly at the any-typed value. This is a minor UX polish — entirely optional.

Proposed diff
     fn diagnostic(ctx: &RuleContext<Self>, _state: &Self::State) -> Option<RuleDiagnostic> {
         let declarator = ctx.query();
         let initializer = declarator.initializer()?;
+        let expression = initializer.expression().ok()?;
         Some(
             RuleDiagnostic::new(
                 rule_category!(),
-                initializer.range(),
+                expression.range(),
                 markup! {
                     "The assigned expression has the type "<Emphasis>"any"</Emphasis>", which undermines type safety."
                 },
crates/biome_js_analyze/tests/specs/nursery/noUnsafeAssignment/valid.ts (1)

23-24: Nitpick: readFileSync doesn't exist on node:fs/promises.

The test still works (the type is unresolved either way), but using fs.readFile(...) or importing from "node:fs" would be more accurate for anyone reading this as an example.

sargunv and others added 2 commits February 12, 2026 13:26
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
- Use expression.range() instead of initializer.range() so the diagnostic
  points at the any-typed value, not the `=` token.
- Change `node:fs/promises` to `node:fs` in valid.ts since readFileSync
  is a sync API from the `fs` module.

https://claude.ai/code/session_01RLJN4W4J3HJ67Acq9eQKCh
Copy link
Member

@ematipico ematipico left a comment

Choose a reason for hiding this comment

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

Please direct this rule against the next branch. We're about to ship a dedicated domain for type-aware lint rules. This would avoid unpleasant conflicts.

The name of the domain is Types

@sargunv sargunv changed the base branch from main to next February 13, 2026 12:02
@sargunv sargunv changed the base branch from next to main February 13, 2026 12:02
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