ts-unused 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,7 +9,8 @@ A CLI tool that analyzes TypeScript projects to find unused exports and unused p
9
9
  - **Finds Unused Exports**: Identifies functions, classes, types, interfaces, and constants that are exported but never imported or used elsewhere
10
10
  - **Finds Completely Unused Files**: Identifies files where all exports are unused, suggesting the entire file can be deleted
11
11
  - **Finds Unused Type Properties**: Detects properties in interfaces and type aliases that are defined but never accessed
12
- - **Auto-Fix Command**: Automatically removes unused exports, properties, and deletes unused files with git safety checks
12
+ - **Finds Never-Returned Types**: Detects union type branches in function return types that are declared but never actually returned
13
+ - **Auto-Fix Command**: Automatically removes unused exports, properties, deletes unused files, and fixes never-returned types with git safety checks
13
14
  - **Structural Property Equivalence**: Handles property re-declarations across multiple interfaces - properties are considered "used" if structurally equivalent properties (same name and type) are accessed in any interface
14
15
  - **Three-Tier Severity System**: Categorizes findings by severity level for better prioritization
15
16
  - **ERROR**: Completely unused code that should be removed
@@ -36,6 +37,7 @@ A CLI tool that analyzes TypeScript projects to find unused exports and unused p
36
37
  | **Goal** | **Report & Analyze** | **Remove (Tree-Shake)** | **Report** |
37
38
  | **Unused Exports** | ✅ Detects and reports | ✅ Detects and removes | ✅ Detects and reports |
38
39
  | **Unused Properties** | ✅ **Unique:** Checks `interface`/`type` properties | ❌ No property checks | ❌ No property checks |
40
+ | **Never-Returned Types** | ✅ **Unique:** Detects unused union branches | ❌ Not supported | ❌ Not supported |
39
41
  | **Test-Only Usage** | ✅ **Unique:** Identifies "Used only in tests" | ⚠️ May delete if not entrypoint | ❌ No distinction |
40
42
  | **Comment Support** | ✅ **Unique:** TODOs change severity | ✅ Skip/Ignore only | ✅ Skip/Ignore only |
41
43
  | **Unused Files** | ✅ Reports completely unused files | ✅ Deletes unreachable files | ✅ Explicit report flag |
@@ -113,7 +115,8 @@ The script outputs:
113
115
  1. **Completely Unused Files**: Files where all exports are unused (candidates for deletion)
114
116
  2. **Unused Exports**: Functions, types, interfaces, and constants that are exported but never used
115
117
  3. **Unused Properties**: Properties in types/interfaces that are defined but never accessed
116
- 3. **Summary**: Total count of unused items found
118
+ 4. **Never-Returned Types**: Union type branches in function return types that are never actually returned
119
+ 5. **Summary**: Total count of unused items found
117
120
 
118
121
  Each finding includes:
119
122
  - File path relative to the project root
@@ -144,9 +147,16 @@ packages/example/src/types.ts
144
147
  UserConfig.futureFeature:12:3-16 [WARNING] (Unused property: [TODO] implement this later)
145
148
  TestHelpers.mockData:8:3-11 [INFO] (Used only in tests)
146
149
 
150
+ Never-Returned Types:
151
+
152
+ packages/example/src/api.ts
153
+ processRequest.ErrorResult:15:17-28 [ERROR] (Never-returned type in union)
154
+ fetchData.TimeoutError:42:25-37 [ERROR] (Never-returned type in union)
155
+
147
156
  Summary:
148
157
  Unused exports: 3
149
158
  Unused properties: 3
159
+ Never-returned types: 2
150
160
  ```
151
161
 
152
162
  ### Example Fix Output
@@ -159,11 +169,15 @@ Fixing: src/helpers.ts
159
169
  Removed unused export: unusedFunction
160
170
  Fixing: src/types.ts
161
171
  Removed unused property: UserConfig.unusedProp
172
+ Fixing: src/api.ts
173
+ ✓ Removed never-returned type 'ErrorResult' from processRequest
174
+ ✓ Removed never-returned type 'TimeoutError' from fetchData
162
175
  Skipped: src/modified.ts (has local git changes)
163
176
 
164
177
  Summary:
165
178
  Fixed exports: 1
166
179
  Fixed properties: 1
180
+ Fixed never-returned types: 2
167
181
  Deleted files: 1
168
182
  Skipped files: 1
169
183
 
@@ -253,6 +267,57 @@ This will:
253
267
 
254
268
  ## Advanced Features
255
269
 
270
+ ### Never-Returned Types Detection
271
+
272
+ The analyzer detects when functions declare union types in their return type signature but never actually return certain branches of that union. This commonly occurs when:
273
+
274
+ - **Error Handling**: Functions declare error types but never return errors in practice
275
+ - **Refactoring**: Code evolution leaves unused type branches behind
276
+ - **Over-Engineering**: Return types are declared too broadly for actual usage
277
+
278
+ **Example:**
279
+
280
+ ```typescript
281
+ interface SuccessResult {
282
+ success: true;
283
+ data: string;
284
+ }
285
+
286
+ interface ErrorResult {
287
+ success: false;
288
+ error: string;
289
+ }
290
+
291
+ type ResultType = SuccessResult | ErrorResult;
292
+
293
+ // ErrorResult is never returned
294
+ export function processData(): ResultType {
295
+ // This function only ever returns SuccessResult
296
+ return { success: true, data: "processed" };
297
+ }
298
+ ```
299
+
300
+ **Detection Capabilities:**
301
+ - Analyzes all function return statements to determine actual return types
302
+ - Handles `Promise<Union>` types for async functions
303
+ - Works with type aliases and direct union declarations
304
+ - Supports primitive unions (`string | number | boolean`)
305
+ - Handles multi-way unions (3+ types)
306
+ - Normalizes boolean literals (`true | false` → `boolean`)
307
+
308
+ **Auto-Fix Behavior:**
309
+ - Removes never-returned types from the union declaration
310
+ - Preserves `Promise<>` wrapper for async functions
311
+ - Simplifies to single type when only one branch remains
312
+ - Skips functions that are completely unused (they get removed entirely)
313
+
314
+ After fixing the example above, the return type would become:
315
+ ```typescript
316
+ export function processData(): SuccessResult {
317
+ return { success: true, data: "processed" };
318
+ }
319
+ ```
320
+
256
321
  ### Structural Property Equivalence
257
322
 
258
323
  The analyzer handles cases where properties are re-declared across multiple interfaces with the same name and type. This commonly occurs with:
@@ -0,0 +1,6 @@
1
+ import { type FunctionDeclaration, type SourceFile } from "ts-morph";
2
+ import type { NeverReturnedTypeResult } from "./types";
3
+ /**
4
+ * Analyzes a function to detect union type branches in the return type that are never actually returned
5
+ */
6
+ export declare function analyzeFunctionReturnTypes(func: FunctionDeclaration, sourceFile: SourceFile, tsConfigDir: string): NeverReturnedTypeResult[];
@@ -0,0 +1,3 @@
1
+ import type { Project, SourceFile } from "ts-morph";
2
+ import type { IsTestFileFn, UnusedPropertyResult } from "./types";
3
+ export declare function analyzeInterfaces(sourceFile: SourceFile, tsConfigDir: string, isTestFile: IsTestFileFn, results: UnusedPropertyResult[], project: Project): void;
@@ -0,0 +1,2 @@
1
+ import type { AnalysisResults, IsTestFileFn } from "./types";
2
+ export declare function analyzeProject(tsConfigPath: string, onProgress?: (current: number, total: number, filePath: string) => void, targetFilePath?: string, isTestFile?: IsTestFileFn): AnalysisResults;
@@ -0,0 +1,5 @@
1
+ import { type Project, type SourceFile, type TypeAliasDeclaration, type TypeElementTypes } from "ts-morph";
2
+ import type { IsTestFileFn, UnusedPropertyResult } from "./types";
3
+ export declare function analyzeTypeLiteralMember(member: TypeElementTypes, typeName: string, sourceFile: SourceFile, tsConfigDir: string, isTestFile: IsTestFileFn, results: UnusedPropertyResult[], project: Project): void;
4
+ export declare function analyzeTypeAlias(typeAlias: TypeAliasDeclaration, sourceFile: SourceFile, tsConfigDir: string, isTestFile: IsTestFileFn, results: UnusedPropertyResult[], project: Project): void;
5
+ export declare function analyzeTypeAliases(sourceFile: SourceFile, tsConfigDir: string, isTestFile: IsTestFileFn, results: UnusedPropertyResult[], project: Project): void;
@@ -0,0 +1,3 @@
1
+ import { Node, type SourceFile } from "ts-morph";
2
+ import type { IsTestFileFn, UnusedExportResult } from "./types";
3
+ export declare function checkExportUsage(exportName: string, declarations: readonly Node[], sourceFile: SourceFile, tsConfigDir: string, isTestFile: IsTestFileFn): UnusedExportResult | null;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Check which files have local git changes (modified, staged, or untracked)
3
+ * Note: Checks the entire git repository, not just the working directory
4
+ * @param workingDir - The directory to check git status in (used to find git root)
5
+ * @returns Set of absolute file paths that have local changes
6
+ */
7
+ export declare function checkGitStatus(workingDir: string): Set<string>;