Skip to content

fix(prefer-describe-function-title): ignore type-only imports - #957

Open
MFA-G wants to merge 2 commits into
vitest-dev:mainfrom
MFA-G:fix/prefer-describe-function-title-type-imports
Open

MFA-G wants to merge 2 commits into
vitest-dev:mainfrom
MFA-G:fix/prefer-describe-function-title-type-imports

Conversation

@MFA-G

@MFA-G MFA-G commented Aug 18, 2026

Copy link
Copy Markdown

Fixes #954.

Problem

A type-only import is erased at compile time, so the identifier does not exist as a value at runtime:

import type { myFunction } from "./myFunction"

describe("myFunction", () => {}) // reported

The rule reports the string title and autofixes it to describe(myFunction, ...), which does not compile — myFunction is a type, not a value. Since the rule is fixable, --fix silently breaks the file.

The check only asked whether the binding was a DefinitionType.ImportBinding, which is true for type-only imports as well.

Fix

Skip bindings whose import is type-only, covering both syntaxes:

function isTypeOnlyImport(definition: Definition): boolean {
  if (definition.type !== DefinitionType.ImportBinding) return false
  return (
    definition.parent.importKind === "type" ||            // import type { x } / import type x
    (definition.node.type === AST_NODE_TYPES.ImportSpecifier &&
      definition.node.importKind === "type")              // import { type x }
  )
}

Applied to both report paths — the string-literal title and the myFunction.name member form, which has the same problem.

Value imports are untouched, so every existing invalid case still reports and fixes as before.

Tests

Three valid cases added, one per syntax (import type { x }, import { type x }, import type x). All three fail on main and pass with the fix.

Validation

  • vitest run → 2378 passed (82 files)
  • tsc --noEmit → clean
  • eslint → clean
  • prettier --check → clean

A type-only binding is erased at compile time, so the identifier does not
exist as a value at runtime. Reporting the string title and autofixing it
to the identifier produced code that does not compile.

Fixes vitest-dev#954
@leeyi45

leeyi45 commented Aug 23, 2026

Copy link
Copy Markdown

Does this also handle the namespace import (import type * as x) case?

@MFA-G

MFA-G commented Aug 24, 2026

Copy link
Copy Markdown
Author

Yes — import type * as x from "./x" is already handled, and I've pushed tests covering it.

import type * as x produces an ImportNamespaceSpecifier whose parent ImportDeclaration carries importKind: "type", so the first branch of isTypeOnlyImport (definition.parent.importKind === 'type') catches it — same path as import type { x } / import type x. The ImportSpecifier branch only exists for the inline import { type x } form, which is the one case where the declaration itself stays importKind: "value".

Added two valid cases in 51155c4 to lock it in:

import type * as myFunction from "./myFunction"
describe("myFunction", () => {})        // string-title path

import type * as myFunction from "./myFunction"
describe(myFunction.name, () => {})     // member-form path

Both fail on main and pass with the fix (the valid list now fails 5/5 without the rule change). Full suite: 2380 passed (82 files); tsc --noEmit, eslint and prettier --check clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

prefer-describe-function-title false positive on type imports

2 participants