Skip to content

💡 Option to treat type-only imports in production code as production dependencies #1909

Description

@filipsobol

Suggest an idea for Knip

Problem

Strict mode reports type-only imports listed in dependencies, expecting them in devDependencies. That is a sensible default for applications, but for published libraries, it conflicts with a placement that is sometimes required: when a type-only import ends up referenced by the emitted .d.ts files, the package must stay in dependencies, or the declarations break in consumer projects that do not hoist it - we learned this from real consumer breakage under Yarn PnP.

In other words, for a library, the correct placement rule is the opposite of what strict mode assumes today: a package imported (even type-only) by production code is a production dependency, because its types become part of the public API surface.

Prior art

Issue #248 asked to analyze the emitted .d.ts files and verify that @types/* packages referenced there are listed in dependencies. It was closed because analyzing emitted output is out of scope, and this limitation is now documented on the known-issues page. This proposal stays within that boundary: it needs no analysis of emitted output at all. Everything required is already visible to Knip in the source - which imports are type-only and whether they occur in production files. The only change is in how strict mode classifies those imports.

Current workaround and why it falls short

Production-scoped ignores work:

ignoreDependencies: [ '@types/hast!', 'hast-util-to-mdast!' ]

but every new type-only production dependency in any workspace needs a new manual entry, the ignore also disables the unused detection for that package in production mode, and the config expresses "ignore this" rather than "our project keeps public-API types in dependencies".

Proposal

An opt-in option — global or per workspace — under which strict mode treats type-only imports in production files as production dependencies. For example:

{ "typesInDependencies": true }

Concretely, given a production source file with:

import type { Root } from 'hast';
  • Today (strict mode): @types/hast in dependencies is reported, because type-only imports are expected in devDependencies.
  • With the option enabled: @types/hast in dependencies satisfies the import and nothing is reported. Unused detection is unaffected — if the import is removed, the package is still reported as unused.
  • Optionally, the rule could go further and report the inverse misplacement: a type-only import in a production file whose package is only in devDependencies, since that placement breaks consumers of the published library. This would give library authors the enforcement Ensure that @types/* used in emitted declarations are in dependencies #248 asked for, without analyzing emitted declarations.

Type-only imports that appear only in test/dev files would keep the current behavior and still belong in devDependencies.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions