Skip to content
Development
Skill

/type-inference

Use this skill when working on Biome's Salsa-backed JavaScript and TypeScript inference, including type-aware lint rules, raw collection or inferred representations, analyzer requests, tracked queries, import or cycle resolution, profiling, and Salsa invalidation tests. Do not

From plugin
biome
26k11 skills
Install
$ npx -y skills add biomejs/biome --skill type-inference --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/type-inference

Context preview

The summary Claude sees to decide when to auto-load this skill.

Use this skill when working on Biome's Salsa-backed JavaScript and TypeScript inference, including type-aware lint rules, raw collection or inferred representations, analyzer requests, tracked queries, import or cycle resolution, profiling, and Salsa invalidation tests. Do not

SKILL.md

type-inference.SKILL.md
name: type-inference
description: Use this skill when working on Biome's Salsa-backed JavaScript and TypeScript inference, including type-aware lint rules, raw collection or inferred representations, analyzer requests, tracked queries, import or cycle resolution, profiling, and Salsa invalidation tests. Do not use for standalone CSS/HTML module-graph data unrelated to JS/TS inference or for ordinary semantic binding analysis.
compatibility: Designed for coding agents working on the Biome codebase (github.com/biomejs/biome).

Salsa-Backed Type Inference

Scope

Use this skill for JavaScript and TypeScript type inference: raw collection, Salsa-backed inferred values, analyzer requests, tracked queries, and inference-specific tests.

Load the corresponding skill for general lint scaffolding, diagnostics, snapshots, or changesets. CSS and HTML module-graph data is outside this skill unless it directly participates in JavaScript or TypeScript inference.

Read the Relevant Guide

Do not load both architecture guides in full for every inference task. Read the sections matching the boundary being changed:

| Task | Canonical guide | | --- | --- | | Raw and inferred representations, collection, inference layers, handles, normalization, work limits | [`biome_js_type_info/CONTRIBUTING.md`](../../../crates/biome_js_type_info/CONTRIBUTING.md) | | Analyzer requests, tracked queries, widening, profiling, Salsa execution tests | [`biome_module_graph/CONTRIBUTING.md`](../../../crates/biome_module_graph/CONTRIBUTING.md) |

Read both guides when changing the architecture across their boundary. Then inspect the implementation files for the specific request, query family, or representation being changed.

Do not use these checked-in files as current examples:

  • `crates/biome_js_type_info/src/resolver.rs`
  • `crates/biome_js_type_info/src/flattening.rs`
  • `crates/biome_js_type_info/src/type.rs`
  • `crates/biome_js_type_info/src/conditionals.rs`
  • `crates/biome_js_type_info/src/helpers.rs`
  • `crates/biome_module_graph/src/js_module_info/module_resolver.rs`

They are not declared by the active crate module trees. Treat them as legacy residue unless the task explicitly concerns removing or migrating them.

Mental Model

Type inference has five layers:

syntax and semantic collection
    -> raw module tables
    -> analyzer-facing requests
    -> tracked Salsa queries
    -> resolver helpers

Collection walks one module without database access. It records raw types, expressions, and binding types in `JsModuleInfo`. A request defines one analyzer-facing result contract. Tracked queries provide memoization and invalidation boundaries. Resolver helpers evaluate references and inferred structures inside those boundaries.

Keep the three type worlds distinct:

| World | Main types | Purpose | | --- | --- | --- | | Raw collector | `TypeData` / `RawTypeData`, `TypeReference`, `RawTypeId`, `TypeStore` | Module-local syntax, declarations, imports, and deferred expressions | | Database-backed | `InferredTypeData<'db>`, `LocalTypeHandle`, `GlobalTypeId` | Inferred values and module ownership in tracked computations | | Analyzer-facing | `InferredType<'db>` | Conservative, bounded inspection for lint rules |

`TypeReference` belongs to the raw world. A lint rule should not pattern-match raw `TypeData` when `InferredType` already provides the required operation.

Inferred data remains owned by the module that declared it. Do not copy another module's inferred payload into the current module, including behind `Arc`. Preserve ownership through references, module-aware handles, global IDs, and tracked queries.

Choose the Narrowest Boundary

The inference levels are alternatives, not sequential phases:

| Need | Boundary | | --- | --- | | Inspect facts collected in one module | Raw local tables | | Resolve one expression, binding, export, member, argument, or classification | Targeted request and tracked query | | Resolve every raw type, expression, and binding in a module | Complete module inference |

A wider boundary is not inherently more correct. Use this decision order when more than one level can answer:

inspect raw local information
    -> return when the local result is conclusive
    -> resolve the smallest selected reference
    -> preserve uncertainty or widen only when the contract requires it
    -> use complete-module inference as the last resort

`infer_module_types` serves contracts that need complete tables. `infer_module_types_bottom_up` is an untracked external scheduler and must not be called from a new tracked query.

Type-Aware Lint Rules

Type-aware JavaScript rules use the analyzer service rather than database queries directly:

1. Declare `domains: &[RuleDomain::Types]` in rule metadata. 2. Use `Typed<N>` as the rule query. 3. Call an existing inference method on `RuleContext`, backed by `TypedService`. 4. Inspect the returned `InferredType` through its bounded helpers. 5. Handle classifications explicitly as `Match`, `NoMatch`, or `Indeterminate`.

Start from `crates/biome_js_analyze/src/services/typed.rs` and search current `Typed<` consumers. Prefer a classification request when a rule asks one property; do not normalize and traverse a complete type when a narrower classifier answers the question.

Changing Raw Inference

When adding syntax-derived type information:

1. Define the raw representation in `crates/biome_js_type_info/src/type_data.rs`. 2. Collect it in `crates/biome_js_type_info/src/local_inference.rs` or `crates/biome_module_graph/src/js_module_info/collector.rs`, preserving unresolved operands as `TypeReference` values. 3. Convert it in `crates/biome_js_type_info/src/interned_types.rs`. 4. Add evaluation under `crates/biome_module_graph/src/db/type_inference/` only when generic raw-to-inferred conversion is insufficient. 5. Audit raw and inferred matches, traversal, and formatting for the new variant.

Collector snapshots p

Read more
Ships withbiome

A toolchain for web projects, aimed to provide functionalities to maintain them. Biome offers formatter and linter, usable via CLI and LSP.

Get the whole plugin
Stats
25,779
Stars
1,231
Forks
Active
Maintenance
Rust
Language
Apache-2.0
License
39m ago
Last commit
3y ago
Created

Repo: biomejs/biome

Other skills on biome.