Skip to content

Show unused public properties and methods #29293

Open

Description

It would be nice to have unused detection expanded, capable of detecting unused methods, exports, etc.

Code Example

Shape.js

class Shape {
    constructor() {
        this.color = 'red';
    }

    colorLog() {
        console.log(this.color);
    }
}

export default Shape;

Circle.js

import Shape from "./Shape";

class Circle extends Shape {
  constructor() {
    super();

    // FIXME: description should show as unused in VSCode, as it does in WebStorm.
    this.description = 'A circle shape';
  }

  // FIXME: circleLog should show as unused in VSCode, as it does in WebStorm.
  circleLog() {
    // NOTE: both VSCode and WebStorm have detected an unused variable.
    const num = 2;

    // NOTE: colorLog is being used, so no unused code errors in Shape.js file.
    super.colorLog();
  }
}

// FIXME: export should show as unused in VSCode, as it does in WebStorm.
export default Circle;

VSCode Screen

screen shot 2019-01-04 at 9 23 48 pm

WebStorm Screen

screen shot 2019-01-04 at 9 23 07 pm

Activity

  1. deleted a comment from vscodebot on Jan 7, 2019
  2. mjbvz commented on Jan 7, 2019

    @mjbvz

    We currently assume that exported members form a public API and therefore are always used. We could try to detect that a certain set of files are an API entrypoints, and then mark unused internal exports. Not sure if there are any issue already tracking this

  3. removed their assignment
    on Jan 7, 2019
  4. changed the title [-]Expand unused detection[/-] [+]Show unused public properties and methods[/+] on Feb 20, 2019
  5. auchenberg commented on Feb 23, 2019

    @auchenberg
  6. zpdDG4gta8XKpMCd commented on Mar 1, 2019

    @zpdDG4gta8XKpMCd

    what about exported but unused

    • modules
    • classes
    • types
    • interfaces/props
    • members (enum | union)
    • functions
    • constants/variables?
  7. fatihturgut commented on Sep 18, 2019

    @fatihturgut

    is there any news about this issue?

  8. jp7837 commented on Oct 16, 2019

    @jp7837

    Update: much faster after adding dummy getProjectVersion implementation assuming the project doesn't change during execution.

    My naive solution below. It's pretty slow even though it should only run a full compilation once. I'll post updates if I improve it.

    const fs = require("fs");
    const ts = require("typescript");
    const path = require("path");
    
    // Copied from https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API#incremental-build-support-using-the-language-services
    function getLanguageService(rootFileNames, options) {
    	const files = {};
    
    	// initialize the list of files
    	rootFileNames.forEach(fileName => {
    		files[fileName] = { version: 0 };
    	});
    
    	// Create the language service host to allow the LS to communicate with the host
    	const servicesHost = {
    		getScriptFileNames: () => rootFileNames,
    		getScriptVersion: fileName => files[fileName] && files[fileName].version.toString(),
    		getScriptSnapshot: fileName => {
    			if (!fs.existsSync(fileName)) {
    				return undefined;
    			}
    
    			return ts.ScriptSnapshot.fromString(fs.readFileSync(fileName).toString());
    		},
    		getCurrentDirectory: () => process.cwd(),
    		getCompilationSettings: () => options,
    		getDefaultLibFileName: options => ts.getDefaultLibFilePath(options),
    		getProjectVersion: () => 1,
    		fileExists: ts.sys.fileExists,
    		readFile: ts.sys.readFile,
    		readDirectory: ts.sys.readDirectory,
    	};
    
    	// Create the language service files
    	const services = ts.createLanguageService(servicesHost, ts.createDocumentRegistry());
    
    	return services;
    }
    
    const tsconfigPath = "tsconfig.gen.json";
    const basePath = path.resolve(path.dirname(tsconfigPath));
    const parseJsonResult = ts.parseConfigFileTextToJson(tsconfigPath, fs.readFileSync(tsconfigPath, { encoding: "utf8" }));
    const tsConfig = ts.parseJsonConfigFileContent(parseJsonResult.config, ts.sys, basePath);
    const services = getLanguageService(tsConfig.fileNames, tsConfig.options);
    
    // For each non-typings file
    tsConfig.fileNames
    	.filter(f => !f.endsWith(".d.ts"))
    	.forEach(file => {
    		const source = ts.createSourceFile(file, fs.readFileSync(file, { encoding: "utf8" }));
    		ts.forEachChild(source, node => {
    			if (ts.isClassDeclaration(node)) {
    				// For each class member
    				node.members.forEach(member => {
    					// If member is marked as public or protected and not a constructor
    					if (
    						(ts.getCombinedModifierFlags(member) & ts.ModifierFlags.Public ||
    							ts.getCombinedModifierFlags(member) & ts.ModifierFlags.Protected) &&
    						member.kind !== ts.SyntaxKind.Constructor
    					) {
    						const references = services.findReferences(file, member.name.pos + 1);
    						// Fail if every reference is a definition and not in a typings file
    						if (
    							references.every(
    								reference =>
    									reference.references.length === 1 &&
    									reference.references[0].isDefinition &&
    									!reference.definition.fileName.endsWith(".d.ts")
    							)
    						) {
    							console.error(`File: ${file} , Member: ${member.name.text}`);
    						}
    					}
    				});
    			}
    		});
    	});
  9. alanhe421 commented on Mar 11, 2020

    @alanhe421

    I was wondering if we could use custom rules to detect and fix this kind of problem

  10. Bogidon commented on Mar 25, 2020

    @Bogidon

    I would like this because using top-level exports, and destructuring imports can clutter your files quite a lot. E.g. I would like to make a Util class I can use the default import on, without worrying about forgetting to delete unused functions a year down the road.

    Or would namespaces be a solution to this problem? (does unused code detection work on namespaces?)

  11. iulianraduat commented on Mar 25, 2020

    @iulianraduat

    I am also interested to remove the kind of dead code mentioned by zpdDG4gta8XKpMCd .

    Maybe Patricio Zavolinsky (pzavolinsky), creator of https://www.npmjs.com/package/ts-unused-exports, can help the Visual Code team to implement it?

  12. 28 remaining items

  13. Papooch commented on May 14, 2024

    @Papooch

    It's not clear how you really figure out [...]

    In my opinion it is very clear that the desired behavior is to do what webstorm already does.

    I'm torn between whether this should be a feature of the language itself or a feature of a separate tool, but in the end, all I really care about is that VSCode can tell me which public methods are unused by the rest of the code (for library code that's not consumed within the same codebase, it is also a good indicator of spotting untested methods)

  14. RyanCavanaugh commented on May 14, 2024

    @RyanCavanaugh
    Member

    I don't know what Webstorm's algorithm is or what its false positives/negatives are. Can you go into more detail on it?

  15. sixtyfive commented on Jun 6, 2024

    @sixtyfive

    So it's 2024 and I had to touch Typescript for the first time today and within a few minutes wished for there to be a visual indicator for an unused method and landed here, in this Issue from 2019. Am I understanding correctly that even after 5 years this is still not possible and people are still being recommended Webstorm instead?

  16. dave0688 commented on Jun 6, 2024

    @dave0688

    You are absolutely correct. This is a shame!
    VS Code is such a nice IDE, but there are some features which are just better in Webstorm...
    I'm thinking of switching, since in quite some issues there is no movement.

  17. ShacharHarshuv commented on Mar 10, 2025

    @ShacharHarshuv

    Lol I just switched from Webstorm to VSCode because of issues in Webstorm... I guess the neighbor's grass is always greener.

    I noticed that vscode has a setting named "typescript.referencesCodeLens.enabled" that is able to detect number of "references" for public methods as well (I assume this feature is provided by typescript). I wonder if it's possible to enable to configure a rule like "if this is 0, it should show as unused"
    I'm not sure if this "algorithm" addresses concerns for false negative/positive pointed out by Ryan Cavanaugh (@RyanCavanaugh), but I assume that many users (including myself) will prefer to use it nontheless, and perhaps it would be a good enough reason to stay in VS Code rather than moving to Webstorm.

    For now I'm trying to use this feature as a workaround, so at least I have some visual indication when something is not used (=not referenced)

  18. webpro commented on Mar 23, 2025

    @webpro
    Contributor

    Author of Knip here. Apart from the discussion what should be built-in to TS or what IDE is better, I just wanted to give a little heads up as to what Knip currently does (not), which might be of relief today:

    • Knip finds unused files, exports and dependencies.
    • From the OP code sample: it should find unused (default) export and it finds unused class members as well
    • Knip is not a generic dead code finder, but built around a module and dependency graph to link up imports and exports. So it does a lot around that, and is less concerned about unused variables/members within a file. So when it comes to public APIs and exports and members of those exports, Knip might be able to help, also with settings such as includeEntryExports and a production mode.
    • It's complementary to e.g. ESLint, tsc and tree-shaking.
    • There are no IDE plugins, there's only a CLI atm. Various reporters, and running the default one has clickable links to files with issues including position. But not the red squigglies yet afaic.

    By the way, recently I've been looking into Unused exported type & interface members. Unfortunately this will likely not be generally released, mostly for being too limited in scope, potential maintenance hell, etc. That said, if a codebase has similar structures as the examples in the provisional docs, it might be interesting to try it out. Who knows.

    Happy to discuss any of this, but please file such feedback and issues specific to Knip in that repo or Discord.

  19. added a commit that references this issue on Mar 24, 2025
  20. triadzack commented on Jul 16, 2025

    @triadzack

    I was not satisfied with this answer and all the tools out there seem to ignore anything "public" so I made a thing to help. See the gist here. I think it could be useful to you but let me know in the comments of the gist if you think it could be better.

    Caveats:

    • It looks at Angular components and assumes if it is not used in the local html file (of the same name) then it is "unused".

    • There are some edgecases accounted for.

      • It ignores HostListener functions and all the ng* lifecycle hooks.

      • It also ignores some types that pretty much always are "unused" in the local html like EventEmitter.

    • It only looks at components with existing html files. It will not look at services or other file types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    In DiscussionNot yet reached consensusSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions