You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Typescript Watch - Cleaning Target Files on Source Deletion #16057
Can we add a compiler option to also glob-delete a target file when the source file is removed? We run into this constantly and have to gulp clean frequently - it makes the usage of tsc -watch pointless as we have to constantly purge the output directory.
For tsc --watch we have a list of output files from the previous iteration, we just need to diff that with the current list, and delete the old outputs.
Reacted by Özgür Uysal, Trym Skaar, Braden Snell, Hossein Saniei, Salvatore Previti, Sasha Kalmikov, Szymon Witamborski, Zheeeng, Roger Padilla, Joachim Wester and 7 more
Is there a recommended way to work around this today? We have prepended rimraf lib/ to our build scripts, which removes the folder containing the compiled JS files.
But this is caused problems with sym-linked modules. The importing project's watch then gets broken with TS2307: Cannot find module, as it only seem to register the disappearance of the lib folder, but not the new one put in its place.
Reacted by WJH, Matt Mazzola, Zheeeng and Thomas Carlsen
Things have gotten a bit more complicated with the addition of the Builder the and the WatchProgram (see #20234), there is not really a place to keep this information, since it is always partial, and we are not rebuilding the information after every change as we used to do. I suppose we could investigate restarting the builder if a file was removed. but we will need a way to detect that in the first place..
This is constantly biting us during development. A file is removed - but nightwatch / some other library still picks it up and runs tests based on code that should not be there.
Last activity on this was more than 8 months ago, but I hope there is still a possibility for this to be added?
Thanks!
Reacted by André, slaneyrw, Alex, Benno, Danny Guo, Jordán Nikolov, AJ Harvey, Mick Dekkers, Gary Bernhardt, Ludovic Radoux and 53 more
My 'solution' is obviously not the full thing that is trying to be implemented right now, it's just some very basic behavior I need myself, But I think it might help some people that need something like this right now. So if it's alright, I will just leave a link here for now: https://www.npmjs.com/package/ts-cleaner
Reacted by ArthurKa
Reacted by Jason Pierce, Cl00e9ment, Andy Pylypchuk and Angelos Pikoulas
This functionality would also be helpful on a simple --clean, this is effecting us in CI and when switching between branches locally
Reacted by Bill Donovan, Andrew Wagner, Ignacio Rios Vazquez, Zachary Stall, Dan, Brevon Good, lemon clown, Shannon Monasco, Joe Klos, Richard Moore and 30 more
Reacted by Gabriel Lein, Richard Moore, BUON Jean-Guy, Paul-E, Christos Panagiotakopoulos, sourcecodes2 and Anders Kjær Damgaard
Also facing this problem, would be a very nice addition
Reacted by Eldar Gabdullin, Ali Yeysideş, Patrick Roza, Yoav Balasiano, Nie, Jason, Arnau Jiménez, Austin Montgomery, Mark Farnum, May Zhong, Gonçalo Tavares and 3 more
Just wanted to add that none of the 3rd party library workarounds mentioned above take care of cleaning up the .tsbuildinfo file. It keeps info about the deleted source file. Probably not a huge deal, but could lead to bloat with large refactors.
Reacted by Anders Kjær Damgaard, Dan Kochetov, Tar and AA
For tsc --watch we have a list of output files from the previous iteration, we just need to diff that with the current list, and delete the old outputs.
I found this issue after a bit of searching since this is still a very common source of bugs and poses an unfortunate workflow problem with tsc --watch. In fact, my initial conclusion is that I should be rolling my own watch that invokes tsc -p on individual files that are changed.
My question here is, why would our approach be to maintain a list of files necessarily? The underlying FS watch should receive events on file deletion or move (typically a "rename" event). On rename, we simply check if a corresponding JS file exists in the outDir that matches the file that had moved or been deleted, and delete that JS file. This is a stateless operation and hopefully shouldn't be too hard to implement, but what am I missing? (this is the approach I am going to take when doing this in user space anyways).
Reacted by james weber, eklenin, Angelos Pikoulas and Adam Sinclair
This a daunting issue, especially if you refactor often, which you should!
And this, is the story about my pursuit to fixing it, the 2023 way! Of course with the help of AI, ChatGTP in particular. So keep reading...
Initially, I googled the issue with "typescript tsc watch remove deleted files", which is how we used to trouble shoot always. Google responded with current issue first, which was frustratingly still open after 6 years (!).
I followed more links but none seemed like solving the problem inherently:
Reading the current issue, I found ts-clean-built to be the best solution & project around at this time. Before even giving it a spin, with only issue, it seemed it would save me hours of wasted effort ;-)
But don't we all have ChatGPT plugins right now, next to the google search? It's just a click away, or as a paid customer you get ALWAYS ChatGPT's answer. Which read as:
ChatGPT
When using tsc with the --watch flag, it will recompile the files every time there is a change in the project directory. However, by default, tsc doesn't remove files that have been deleted from the project directory. To remove the deleted files from the output directory, you can use the --removeComments flag.
Here's an example command that uses both --watch and --removeComments:
tsc --watch --removeComments
The --removeComments flag removes all comments from the output files and also removes any files that no longer exist in the source directory.
If you want to keep comments in the output files, you can use the --clean flag instead, which removes any files that no longer exist in the source directory without removing comments:
tsc --watch --clean
Note that if you are using a version of tsc older than 3.8, the --removeComments flag will not work as intended. Instead, you can use the --preserveWatchOutput flag, which will also remove deleted files:
tsc --watch --preserveWatchOutput
Keep in mind that this flag is only available in TypeScript version 3.8 and newer.
Wow! Is that true? Did Chat GPT overwhelmingly solved my ;issue with one --clean commmand, but googled failed to tell me?
So I immediately added the --clean flag to my scripts: npx tsc --watch --clean -p tsconfig.json. Of course it failed:
error TS5093: Compiler option '--clean' may only be used with '--build'.
So I tried on last thing, although I was sure its doomed. According to ChatGPT The --removeComments flag removes all comments from the output files and also removes any files that no longer exist in the source directory.. Lets see:
As one would expect, it doesn't, it is just to Disable emitting comments..
So ChatGPT lied and tried to fool me twice in one problem, as many as the solutions! Welcome to the Brave New World of lies, AI powered!
TypeScript team, please, please solve this issue! Till then I'm going for ts-clean-built!
Reacted by J++ and Ivan Sabelnikov
Reacted by Robert Kieffer
Reacted by Simon Reinisch, Weston Thayer, Tino Siegmund, Tar, May Zhong, TeamDman, Anders Kjær Damgaard, Michal Pácal, Jianrong Yu, Jeongho Nam and 5 more
To anyone looking for a solution, I've completely stopped using tsc --watch and instead relied on chokidar-cli for watching over my files and triggering the tsc build command.
I don't know if it is as efficient as tsc --watch command but at least it works.
#!/usr/bin/env node
/** * Deletes files from dist/ that do not exist in src/ */constfs=require('fs')constpath=require('path')const{ program }=require('commander')program.requiredOption('--src <source dir>','Source directory').requiredOption('--dist <destination dir>','Destination directory').option('--verbose','Print deleted file names').option('--silent','Print nothing')program.parse(process.argv)constoptions=program.opts()constsrcDir=path.resolve(options.src)constdistDir=path.resolve(options.dist)letremovedFilesCount=0constgetCorrespondingSrcFile=(distFile)=>{constrelPath=path.relative(distDir,distFile)constsrcFileTs=path.join(srcDir,relPath.replace(/\.js$/,'.ts'))constsrcFileJson=path.join(srcDir,relPath)if(fs.existsSync(srcFileTs))returnsrcFileTsif(fs.existsSync(srcFileJson))returnsrcFileJsonreturnnull}constcleanDist=(distPath)=>{if(!fs.existsSync(distPath)){console.error(`Dist directory does not exist: ${distPath}`)process.exit(1)}constfilesToCheck=fs.readdirSync(distPath,{withFileTypes: true})for(constfileoffilesToCheck){constdistFilePath=path.join(distPath,file.name)if(file.isDirectory()){cleanDist(distFilePath)if(fs.readdirSync(distFilePath).length===0){fs.rmdirSync(distFilePath)}continue}constcorrespondingSrcFile=getCorrespondingSrcFile(distFilePath)if(!correspondingSrcFile){removedFilesCount++if(!options.silent){if(options.verbose){console.log(`Removing: ${distFilePath}`)}}fs.unlinkSync(distFilePath)}}}cleanDist(distDir)if(!options.silent){console.log(`Total old files removed: ${removedFilesCount}`)}
I realize that the advantage of tsc -- watch is that it is not forced to compile everything every time you change a few files, but this feature would be sooo nice if it is not too much of a nightmare to implement.
Reacted by Maksym Kobieliev, François Lamboley and Sachin Meier
Activity
mhegazy commentedon Aug 23, 2017
For
tsc --watchwe have a list of output files from the previous iteration, we just need to diff that with the current list, and delete the old outputs.timm-gs commentedon Nov 14, 2017
Is there a recommended way to work around this today? We have prepended
rimraf lib/to our build scripts, which removes the folder containing the compiled JS files.But this is caused problems with sym-linked modules. The importing project's watch then gets broken with
TS2307: Cannot find module, as it only seem to register the disappearance of thelibfolder, but not the new one put in its place.admosity commentedon Mar 20, 2018
Can someone provide some pointers where I can help implement this? Mohamed Hegazy (@mhegazy)?
mhegazy commentedon Mar 29, 2018
Things have gotten a bit more complicated with the addition of the Builder the and the WatchProgram (see #20234), there is not really a place to keep this information, since it is always partial, and we are not rebuilding the information after every change as we used to do. I suppose we could investigate restarting the builder if a file was removed. but we will need a way to detect that in the first place..
bes commentedon Jan 11, 2019
Hi!
This is constantly biting us during development. A file is removed - but nightwatch / some other library still picks it up and runs tests based on code that should not be there.
Last activity on this was more than 8 months ago, but I hope there is still a possibility for this to be added?
Thanks!
nullxone commentedon May 20, 2019
If you're using jest, you can use ts-jest
TarVK commentedon May 21, 2019
My 'solution' is obviously not the full thing that is trying to be implemented right now, it's just some very basic behavior I need myself, But I think it might help some people that need something like this right now. So if it's alright, I will just leave a link here for now: https://www.npmjs.com/package/ts-cleaner
beverts312 commentedon Jun 4, 2019
This functionality would also be helpful on a simple
--clean, this is effecting us in CI and when switching between branches locally5 remaining items
felipeggrod commentedon May 5, 2021
Still causing problems...
rbrcurtis commentedon May 10, 2021
I would think this feature could use the build info from —incremental to know what needs to be deleted.
DylanCulfogienis commentedon May 19, 2021
Any updates on this?
akd-io commentedon Jul 29, 2021
Also facing this problem, would be a very nice addition
theomessin commentedon Nov 2, 2021
Bump
WestonThayer commentedon Jan 13, 2022
Just wanted to add that none of the 3rd party library workarounds mentioned above take care of cleaning up the
.tsbuildinfofile. It keeps info about the deleted source file. Probably not a huge deal, but could lead to bloat with large refactors.jeremyong commentedon Dec 21, 2022
I found this issue after a bit of searching since this is still a very common source of bugs and poses an unfortunate workflow problem with
tsc --watch. In fact, my initial conclusion is that I should be rolling my own watch that invokestsc -pon individual files that are changed.My question here is, why would our approach be to maintain a list of files necessarily? The underlying FS watch should receive events on file deletion or move (typically a "rename" event). On rename, we simply check if a corresponding JS file exists in the
outDirthat matches the file that had moved or been deleted, and delete that JS file. This is a stateless operation and hopefully shouldn't be too hard to implement, but what am I missing? (this is the approach I am going to take when doing this in user space anyways).anodynos commentedon Feb 16, 2023
This a daunting issue, especially if you refactor often, which you should!
And this, is the story about my pursuit to fixing it, the 2023 way! Of course with the help of AI, ChatGTP in particular. So keep reading...
Initially, I googled the issue with
"typescript tsc watch remove deleted files", which is how we used to trouble shoot always. Google responded with current issue first, which was frustratingly still open after 6 years (!).I followed more links but none seemed like solving the problem inherently:
Reading the current issue, I found ts-clean-built to be the best solution & project around at this time. Before even giving it a spin, with only issue, it seemed it would save me hours of wasted effort ;-)
But don't we all have ChatGPT plugins right now, next to the google search? It's just a click away, or as a paid customer you get ALWAYS ChatGPT's answer. Which read as:
Wow! Is that true? Did Chat GPT overwhelmingly solved my ;issue with one
--cleancommmand, but googled failed to tell me?So I immediately added the
--cleanflag to my scripts:npx tsc --watch --clean -p tsconfig.json. Of course it failed:ChatGPT let down No 1. For a start,
--cleancan be used only along side--buildfor some reason something ChatGPT could and maybe should have known! Not sure about the dates tho.So, lets try again:
npx tsc --clean --watch --build -p tsconfig.jsonAnd this time I get:
ERROR: "error TS6369: Option '--build' must be the first command line argument.Why so stringent? Another try...
npx tsc --build --clean --watch -p tsconfig.jsonGuess what! Two errors this time!
Ok, I had enough! In any case,
--build --cleanare useless when watching, its doesnt "mirror"src/todist/amd has a myriad of issues - see https://stackoverflow.com/questions/68144771/whats-the-difference-between-tsc-build-clean-vs-rm-rf-jsSo I tried on last thing, although I was sure its doomed. According to ChatGPT The --removeComments flag removes all comments from the output files and also removes any files that no longer exist in the source directory.. Lets see:
tsc --watch --removeCommentsAs one would expect, it doesn't, it is just to
Disable emitting comments..So ChatGPT lied and tried to fool me twice in one problem, as many as the solutions! Welcome to the Brave New World of lies, AI powered!
TypeScript team, please, please solve this issue! Till then I'm going for
ts-clean-built!alexandrubau commentedon Feb 15, 2024
To anyone looking for a solution, I've completely stopped using
tsc --watchand instead relied on chokidar-cli for watching over my files and triggering thetscbuild command.I don't know if it is as efficient as
tsc --watchcommand but at least it works.{ "name": "myproject", "scripts": { "watch": "chokidar \"src/*\" \"tsconfig.json\" -c \"npm run build\" --initial", "build": "rimraf dist && tsc" }, "devDependencies": { "@types/node": "^20.11.17", "chokidar-cli": "^3.0.0", "rimraf": "^5.0.5", "typescript": "^5.3.3" } }Crestanzio commentedon May 19, 2024
For anyone have this problem like me, i have made a library to solve this, and many more, take a look. typemon
KROT47 commentedon Feb 4, 2025
I came up with this solution:
onchangepackage.json{ "scripts": { "clean": "./scripts/delete_old_files.cjs --dist dist --src src", "watch": "concurrently \"tsc -w\" \"onchange -f unlink 'src/**/*' -- yarn clean\"", "build": "yarn clean && tsc" } }./scripts/delete_old_files.cjssputnik-adam commentedon Feb 26, 2025
It is now 2025 😬
joshjung commentedon Mar 10, 2025
I realize that the advantage of tsc -- watch is that it is not forced to compile everything every time you change a few files, but this feature would be sooo nice if it is not too much of a nightmare to implement.
Watch mode: clean up output files when source files are deleted