{"id":22787013,"url":"https://github.com/line/tsr","last_synced_at":"2025-08-09T17:31:51.065Z","repository":{"id":195929379,"uuid":"690917518","full_name":"line/tsr","owner":"line","description":"TypeScript Remove (tsr) is a utility that removes unused code from TypeScript projects – It's like tree shaking, but for source files [formerly ts-remove-unused]","archived":false,"fork":false,"pushed_at":"2024-12-10T17:06:17.000Z","size":1739,"stargazers_count":1032,"open_issues_count":5,"forks_count":12,"subscribers_count":8,"default_branch":"main","last_synced_at":"2024-12-10T18:20:37.683Z","etag":null,"topics":["typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/tsr","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/line.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-09-13T06:28:51.000Z","updated_at":"2024-12-10T17:56:03.000Z","dependencies_parsed_at":"2024-10-23T09:37:24.490Z","dependency_job_id":"432beacc-6fbc-4f14-9c4b-d4fbb3ce8018","html_url":"https://github.com/line/tsr","commit_stats":null,"previous_names":["line/ts-remove-unused","line/tsr"],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/line%2Ftsr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/line%2Ftsr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/line%2Ftsr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/line%2Ftsr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/line","download_url":"https://codeload.github.com/line/tsr/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229309030,"owners_count":18053039,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["typescript"],"created_at":"2024-12-12T00:01:29.781Z","updated_at":"2025-08-09T17:31:51.029Z","avatar_url":"https://github.com/line.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg width=\"180\" src=\"./media/icon.svg\" alt=\"TypeScript Remove (tsr) logo\" /\u003e\n\u003c/div\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://badge.fury.io/js/tsr\"\u003e\u003cimg alt=\"npm version\" src=\"https://badge.fury.io/js/tsr.svg\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://packagephobia.com/result?p=tsr\"\u003e\u003cimg alt=\"install size\" src=\"https://packagephobia.com/badge?p=tsr\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/tsrorg/tsr/actions/workflows/ci.yml\"\u003e\u003cimg alt=\"CI\" src=\"https://github.com/tsrorg/tsr/actions/workflows/ci.yml/badge.svg?branch=main\" /\u003e\u003c/a\u003e\n\u003c/div\u003e\n\n\u003e Notice: This project is currently suspended.\n\u003e Pull requests will be reviewed on an irregular basis, but please note that the development team will not be adding new features for the time being.\n\n# tsr\n\nTypeScript Remove (tsr) is a utility that removes unused code from TypeScript projects – It's like tree shaking, but for source files\n\nEnglish | [한국어](./README_ko.md)\n\n[Migrating from v0.x (ts-remove-unused)](./doc/migration.md)\n\n## Features\n\n### 🕵️ Find unused code\n\ntsr statically analyses your TypeScript project like how tree-shaking is implemented in bundlers. Run tsr to get a list of unused exports and files (modules) in your TypeScript project. Use tsr in your CI pipeline to detect unused code from being added.\n\n### 🧹 Remove unused code automatically\n\ntsr is built for automatic code removal. Not only does tsr remove the `export` keyword from unused declarations, it will remove the whole declaration if the declaration not used within the file. tsr will also remove imports and other local declarations that became unnecessary after removing the declaration. [Check out the examples of how tsr edits your files.](#examples)\n\n### 📦 Works out of the box\n\ntsr uses the TypeScript compiler to detect files in your project and resolve imports. The only requirement is a valid `tsconfig.json`. There's no need to setup another config file to get tsr running. Specify your entrypoint file and start using tsr in seconds.\n\n## Install\n\n```bash\nnpm i tsr\n```\n\nTypeScript is a peer dependency.\n\n## Quick Start\n\n1. **🔍 Check your `tsconfig.json`** – Make sure `include` and `exclude` are configured thoroughly so that tsr can correctly detect unused code.\n\n2. **🔍 Check your entrypoint files** – Without entrypoint files, all files are unnecessary. Usually it is some file like `src/main.ts` or maybe a group of files like `src/pages/*`.\n\n3. **🚀 Execute** – Pass regex patterns that match the entrypoints. Use `--write` to change the files in place.\n\n```bash\nnpx tsr 'src/main\\.ts$'\n```\n\n## Usage\n\n### CLI\n\n\u003c!-- prettier-ignore-start --\u003e\n\n```\n\nUsage:\n  tsr [options] [...entrypoints]\n\nOptions:\n  -p, --project \u003cfile\u003e    Path to your tsconfig.json\n  -w, --write             Write changes in place\n  -r, --recursive         Recursively look into files until the project is clean\n  --include-d-ts          Check for unused code in .d.ts files\n  -h, --help              Display this message\n  -v, --version           Display version number\n\nExamples:\n  # Check unused code for a project with an entrypoint of src/main.ts\n  tsr 'src/main\\.ts$'\n\n  # Write changes in place\n  tsr --write 'src/main\\.ts$'\n\n  # Check unused code for a project with a custom tsconfig.json\n  tsr --project tsconfig.app.json 'src/main\\.ts$'\n\n  # Check unused code for a project with multiple entrypoints in src/pages\n  tsr 'src/pages/.*\\.ts$'\n\n```\n\u003c!-- prettier-ignore-end --\u003e\n\n#### `-p`, `--project`\n\nSpecifies the `tsconfig.json` that is used to analyze your codebase. Defaults to `tsconfig.json` in your project root.\n\n```bash\nnpx tsr --project tsconfig.client.json 'src/main\\.ts$'\n```\n\n#### `-w`, `--write`\n\nWrites fixable changes in place.\n\n\u003e [!WARNING]\n\u003e This will delete code. Using it in a git controlled environment is highly recommended.\n\n#### `-r`, `--recursive`\n\nThe default behavior of the CLI is to process all files once. Some issues may not be detected if the unused code is a result of the modification of another file in the project. When this option is enabled, tsr will recursively look into files that may be affected by a file edit.\n\nThis will take longer but is helpful when you want to edit in one pass.\n\n#### `--include-d-ts`\n\nBy default, exported types in `.d.ts` files are not detected. Use the `--include-d-ts` option if you want to include types in `.d.ts` files.\n\n### JavaScript API\n\nAlternatively, you can use the JavaScript API to execute tsr.\n\n```typescript\nimport { tsr } from 'tsr';\n\nawait tsr({\n  entrypoints: [/main\\.ts/],\n  mode: 'check',\n}).catch(() =\u003e {\n  process.exitCode = 1;\n});\n```\n\nThe project path and/or the custom `tsconfig.json` can be manually specified.\n\n```typescript\nawait tsr({\n  entrypoints: [/main\\.ts/],\n  mode: 'check',\n  configFile: 'tsconfig.sample.json',\n  projectRoot: '/path/to/project',\n});\n```\n\nCheck the type definition `import('tsr').Config` for all of the available options.\n\n## Skip\n\nWhen you add a comment `// tsr-skip` to your export declaration, it will be skipped from being removed.\n\n```ts\n// tsr-skip\nexport const hello = 'world';\n```\n\n## Test files\n\nIf you have a separate tsconfig for tests using [Project References](https://www.typescriptlang.org/docs/handbook/project-references.html), that would be great! tsr will remove exports/files that exist for the sake of testing.\n\nIf you pass a `tsconfig.json` to the CLI that includes both the implementation and the test files, tsr will remove your test files since they are not referenced by your entry point file by default. You can avoid tests being deleted by passing a pattern that matches your test files to the args in the meantime, but the recommended way is to use project references to ensure your TypeScript config is more robust and strict (not just for using this tool).\n\n```bash\nnpx tsr -w 'src/main\\.ts$' ## depending on the tsconfig, this will delete test files\nnpx tsr -w 'src/main\\.ts$' '.*\\.test\\.ts$' ## Specifying test files as entrypoints will avoid deletion\n```\n\n## Comparison\n\n### TypeScript\n\nIf you enable `compilerOptions.noUnusedLocals`, declarations that are never read will be reported.\n\n```typescript\n// 'a' is declared but its value is never read.\nconst a = 'a';\n```\n\nHowever, when you `export` it, no errors will be reported regardless of its usage within the project. tsr's aim is to report/fix unused code while taking project wide usage into account.\n\n### ESLint\n\nESLint will detect unused imports. Plugins such as `eslint-plugin-unused-imports` can also auto-fix this issue.\n\n```typescript\n// 'foo' is defined but never used.\nimport { foo } from './foo';\n```\n\nHowever, we can't detect unused exports. ESLint's architecture works in a file by file basis and was never intended to provide linting based on project-wide usage stats.\n\n```typescript\n// a lint rule that detects if this export is used within the project is unlikely to be introduced\nexport const a = 'a';\n```\n\ntsr's main goal is to remove unused exports and delete unused modules, but it will also delete unused imports that are a result of removing an export declaration.\n\n### Knip\n\nKnip aims to be a comprehensive solution around the idea of detecting unused code (and even dependencies) in repositories. While there are obvious differences like tsr supporting TypeScript projects only, here are some notable differences.\n\n#### Built for automatic editing\n\ntsr was designed for automatic code editing from the beginning. Knip currently does support automatic fixing, however there are limitations to what it provides. For example, given the following code:\n\n```typescript\nexport const a = 'a';\n\nexport const f = () =\u003e a2;\n\nconst a2 = 'a2';\n```\n\nWhen `f()` is not used within the project,\n\n- Knip will only remove the `export` keyword\n- tsr will remove the whole declaration of `f()` and will also remove `a2`\n\n#### Zero Configuration\n\nKnip expects users to provide a config file. While this adds the flexibility, it's difficult to correctly configure Knip to suit your needs. tsr relies on `tsconfig.json` to avoid additional setup. If you have a `tsconfig.json` configured in your repository, it works out of the box.\n\n#### Less ambiguity\n\nKnip makes some assumptions on how your project is structured to detect code usage. Also, Knip has a custom module resolution behavior. While these design decisions might be helpful for some users and opens the possibility to support file types that TypeScript can't handle, the behavior becomes less predictable.\n\ntsr's behavior is clear by design. TypeScript is used to detect modules in your project and to resolve import statements so you can take full control with `tsconfig.json`. Basically, if your project passes type checking, tsr will work. If tsc fails, tsr will also fail to produce the correct results.\n\n#### Minimal Design\n\ntsr is designed to be minimal and serve a single purpose. The install size is substantially smaller. Also, tsr is runtime dependent, not relying on `@types/node`.\n\n| tsr  | Knip   |\n| ---- | ------ |\n| 98kB | 5.86MB |\n\n#### Better Performance\n\nOur benchmark shows that tsr is 2.14x faster compared to Knip 🚀 (see `benchmark/vue_core.sh` for details)\n\n\u003cimg width=\"400\" src=\"./media/comparison.png\" alt=\"benchmark of tsr and Knip\" /\u003e\n\n#### Recursive Editing\n\ntsr provides `--recursive` option which will edit your files until there are no unused code in one pass.\n\n#### Key Differences\n\n| Feature                  | tsr                           | Knip                                       |\n| ------------------------ | ----------------------------- | ------------------------------------------ |\n| **Automatic Editing**    | ✅ Comprehensive              | Limited                                    |\n| **Zero Configuration**   | ✅ Works with `tsconfig.json` | Requires a config file for correct results |\n| **Predictable Behavior** | ✅ TypeScript-based logic     | Assumptions for project structure          |\n| **Install Size**         | ✅ 98kB, minimal dependencies | 5.86MB, requires `@types/node`             |\n| **Performance**          | ✅ 2.14x faster               |                                            |\n| **Recursive Editing**    | ✅ `--recursive` option       |                                            |\n\n## Examples\n\nHere are some examples of how tsr edits your files when it finds unused code.\n\n\u003c!-- prettier-ignore-start --\u003e\n\nWhen `a2` is not used within the project:\n\n```diff\n--- src/a.ts\n+++ src/a.ts\n@@ -1,3 +1 @@\n export const a = 'a';\n-\n-export const a2 = 'a2';\n```\n\nWhen `b` is not used within the project but `f()` is used within the project:\n\n```diff\n--- src/b.ts\n+++ src/b.ts\n@@ -1,5 +1,5 @@\n-export const b = 'b';\n+const b = 'b';\n \n export function f() {\n     return b;\n }\n```\n\nWhen `f()` is not used within the project and when deleting it will result in `import` being unnecessary:\n\n```diff\n--- src/c.ts\n+++ src/c.ts\n@@ -1,7 +1 @@\n-import { cwd } from \"node:process\";\n-\n export const c = 'c';\n-\n-export function f() {\n-    return cwd();\n-}\n```\n\nWhen `f()` and `exported` are not used within the project and when deleting `f()` will result in `exported` and `local` being unnecessary:\n\n```diff\n--- src/d.ts\n+++ src/d.ts\n@@ -1,8 +1 @@\n-export const exported = \"exported\";\n-const local = \"local\";\n-\n export const d = \"d\";\n-\n-export function f() {\n-  return { exported, local };\n-}\n\n```\n\n\u003c!-- prettier-ignore-end --\u003e\n\n## Contributing\n\nContributions are welcomed!\n\n## Author\n\nKazushi Konosu (https://github.com/kazushisan)\n\n## License\n\n```\nCopyright (C) 2023 LINE Corp.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fline%2Ftsr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fline%2Ftsr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fline%2Ftsr/lists"}