Languages / TypeScript
TypeScript static analysis: unused exports, complexity and call graphs
To find unused exports and files in TypeScript, Knip is the standard single-ecosystem tool. repowise reaches the same kind of findings from a full import and call graph: tsconfig paths, npm, yarn and pnpm workspaces and package.json exports are resolved, Next.js and NestJS entry points are known, and each finding carries a confidence from git history.
Last reviewed: November 2026
Full tier
What repowise detects in TypeScript
Checked against the engine source. Every row runs locally with zero LLM calls.
| Files parsed | .ts, .tsx, .mts, .cts |
|---|---|
| Import resolution | Full. tsconfig and jsconfig paths with baseUrl fallback, npm, yarn and pnpm workspaces, package.json exports (wildcards included), # subpath imports, export * barrels, React Native platform suffixes |
| Call graph | Resolved calls with confidence per edge, heritage and type references |
| Dead code | Unreachable files, unused exports, zombie workspace packages; deletion-ready flag on unused exports |
| Health markers | Complexity, class metrics, Extract Method plans, assertion-free tests and mock saturation in Jest and Vitest suites |
| Performance markers | I/O and Prisma queries in loops, serial await, JSON.parse in loops, spread in reduce, nested quadratic loops |
| Coverage reports | lcov (Jest, Vitest, c8, nyc), Cobertura, Clover |
| Frameworks recognised | Next.js App Router and pages, NestJS modules, Express, Hono, Fastify, Koa, tRPC, Remix, Angular, test-runner setup files |
Specific to this language
How TypeScript code is read
Monorepo resolution is the hard part
A TypeScript monorepo imports through aliases: tsconfig paths, workspace package names and package.json exports maps. repowise resolves all three, maps build output back to source, and follows export * barrels, so an export used only through a barrel in another package is still counted as used.
Next.js and NestJS files are entry points
App Router files (page, layout, route, middleware, template, error, loading, not-found) and pages-router routes are roots, so they are never reported as unreachable. NestJS @Module controllers, providers, imports and exports become edges, as do tRPC procedures and Hono, Fastify and Koa route handlers.
Dynamic loading is read, not ignored
import(), require(), require.context, import.meta.glob, React.lazy, next/dynamic, jest.mock and vi.mock mark nearby files as possibly loaded at runtime. Those files stay at the review tier, and deletion-ready is reserved for findings with no runtime-load signal.
Honest comparison
Native TypeScript tools, and when they are enough
| Tool | What it covers |
|---|---|
| Knip | Unused files, exports, types and dependencies, with plugins for many frameworks and an auto-fix mode. The strongest single-ecosystem choice. |
| tsc --noUnusedLocals | Unused locals and parameters inside a file. Says nothing about unused exports. |
| ts-prune | Unused exports only. Its README marks it as in maintenance mode and points to Knip. |
| ESLint | no-unused-vars and the complexity rule, per file. |
| dependency-cruiser, madge | Module dependency graphs, cycle detection and import rules. |
Where repowise adds value
- A confidence on every finding from git history and runtime-load signals, plus a deletion-ready flag an agent can act on.
- The same pass covers the Python, Go or Java services in the repository, in one graph.
- Health, performance markers (Prisma queries in loops, serial await) and hotspots on the same files.
- get_dead_code over MCP, so Claude Code, Cursor or Codex can ask for deletion-ready findings directly.
How to run it
Analyse a TypeScript repository
From the repository root. Agents get the same results through the get_dead_code, get_health and get_context MCP tools.
uv tool install repowise # or: pipx install repowise
repowise init --yes --no-prose # index the repo, no API key
repowise dead-code --min-confidence 0.7 --safe-only
repowise health --refactoring-targets
npx vitest run --coverage --coverage.reporter=lcov
repowise coverage add coverage/lcov.info
repowise serve # graph, health and dead code in a local dashboardQuestions
What people ask before they try it.
Is repowise a Knip alternative?
Knip is built for the TypeScript ecosystem and can fix what it finds. repowise adds to it when the repository mixes languages, when you want each finding ranked by git history and runtime-load risk, or when an agent needs the findings over MCP with a deletion-ready flag. Many teams run both.
Does it understand tsconfig paths and pnpm workspaces?
Yes. tsconfig and jsconfig paths aliases, baseUrl, npm, yarn and pnpm workspaces (pnpm-workspace.yaml), package.json exports maps including wildcards, and Node # subpath imports are all resolved before dead code runs.
Will it report my Next.js pages as unused?
No. App Router files and pages-router routes are framework entry points. They are roots of the graph, so the files they import are reachable too.
How do I see the call graph of a TypeScript project?
Run repowise init, then repowise serve to explore the dependency and call graph, communities and C4 views in the local dashboard. Agents get the same edges through get_context with include=["callers"].
Does repowise send my TypeScript code to an LLM?
No. Parsing, the call graph, dead code, health scores, performance markers and git history all run locally with zero LLM calls. repowise init --yes --no-prose needs no API key, and the analysis itself makes no network calls. Written documentation prose is the one opt-in step that uses a model, and it can run on a local Ollama model.
Related reading
Index a TypeScript repository.
Public repositories are free on repowise.dev. The CLI is open source and runs on your machine with no API key.