Skip to content

Use files from tsconfig references with --use-tsconfig-files - #2126

Merged
webpro merged 2 commits into
webpro-nl:mainfrom
kaanisthatyou:fix/tsconfig-references-files
Oct 7, 2026
Merged

webpro merged 2 commits into
webpro-nl:mainfrom
kaanisthatyou:fix/tsconfig-references-files

Conversation

@kaanisthatyou

@kaanisthatyou kaanisthatyou commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Closes #2116.

With a solution-style tsconfig.json ("files": [] plus references, as create-vite generates), --use-tsconfig-files found no project files and Knip reported nothing. The editor extension, MCP server and language server hit the same case, since they enable the flag when there is no Knip config.

With --use-tsconfig-files, loadTSConfig now also loads the tsconfigs referenced at or below its own directory (./tsconfig.app.json, ./tsconfig.node.json) and adds their files. References that point up or sideways (../lib) are dependencies built as separate projects and are not followed. The default mode is unchanged: there the referenced .d.ts files would become entries, which ambient-declaration-files.test.ts rules out.

Tests: tsc-files-mode-references is the tsc-files-mode fixture in solution style and expects the same results (the first test fails on main). tsc-files-mode-references-workspaces checks that a reference to another workspace (here in ignoreWorkspaces) does not add its files. The repro from the issue now reports orphan, same as with a single tsconfig.

@webpro webpro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for picking this up! Following references in --use-tsconfig-files mode is the right direction, and leaving the default mode alone makes sense given ambient-declaration-files.test.ts. Requesting changes to the reference walk: it should stay within the project, and loadTSConfig can do it by recursing into itself (see inline comment).

Comment thread packages/knip/src/util/load-tsconfig.ts Outdated
}
};

const expandReferencedFileNames = (

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In project-reference setups a package's tsconfig usually references its dependencies, e.g. "references": [{ "path": "../lib" }]. tsc -b builds ../lib as a separate project, and its source files are not part of the referencing program. Following those references turns another package's files into project files of this workspace:

  • Issues in an ignoreWorkspaces workspace get reported. Repro: packages/app/tsconfig.json with "include": ["src"], "references": [{ "path": "../ign" }], no root tsconfig, and { "ignoreWorkspaces": ["packages/ign"] }. On main only app and lib issues are reported; with this PR the unused exports in packages/ign show up too.
  • Each workspace globs the transitive closure of its references. In a synthetic chain of 100 packages where each references the previous one, --use-tsconfig-files goes from 0.5s to 1.7s with identical output.

References that point up or sideways are dependencies. The ones at or below the referencing tsconfig's directory (./tsconfig.app.json, ./tsconfig.node.json, ./tsconfig.lib.json) are part of the project. With that rule, loadTSConfig can recurse into the references itself, which also removes the duplicated include/exclude/files/outDir handling:

export const loadTSConfig = async (
  tsConfigFilePath: string,
  isUseTscFiles = false,
  visited = new Set([tsConfigFilePath])
): Promise<TSConfigInfo> => {
    const fileNames = expandFileNames(dir, compilerOptions, include, exclude, files);
    if (isUseTscFiles && config.references) {
      for (const ref of config.references) {
        const refPath = resolveReference(ref.path, dir);
        if (!refPath?.startsWith(`${dir}/`) || visited.has(refPath)) continue;
        visited.add(refPath);
        for (const filePath of (await loadTSConfig(refPath, true, visited)).fileNames) fileNames.push(filePath);
      }
    }

A fixture like the repro above would make a good regression test.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks, done in bc2615c: loadTSConfig recurses into references at or below its own directory, and expandReferencedFileNames is gone. Your repro is the new tsc-files-mode-references-workspaces fixture (app references ../ign, which is in ignoreWorkspaces): it fails on the previous commit with the ign export reported, and passes now. tsc-files-mode-references still passes.

References that point up or sideways are dependencies built as separate
projects, so their files must not become project files of the workspace.
loadTSConfig now recurses into the references at or below its directory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@webpro webpro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the quick update, looks good!

@pkg-pr-new

pkg-pr-new Bot commented Oct 7, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/knip@2126
npm i https://pkg.pr.new/@knip/language-server@2126
npm i https://pkg.pr.new/@knip/mcp@2126

commit: bc2615c

@webpro
webpro merged commit 9618185 into webpro-nl:main Oct 7, 2026
29 checks passed
@webpro

webpro commented Oct 9, 2026

Copy link
Copy Markdown
Member

πŸš€ This pull request is included in v6.41.0. See Release 6.41.0 for release notes.

Using Knip in a commercial project? Please consider becoming a sponsor.

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.

πŸ› --use-tsconfig-files finds no files with a solution-style tsconfig

2 participants