lint-staged/lint-staged

Build typescript on commit

Closed this issue ยท 23 comments

I'm trying to rebuild my typescript project on each commit, after prettifying the code with prettier:

"lint-staged": {
    "*.ts": [
      "prettier --parser typescript --write --no-semi",
      "tsc",
      "git add"
    ]
  },

Problem is that the tsc command here seems to fail to see my .tsconfig.json file, probably because the working directory of lint-staged is set to the directory of the file that is committed.

Is there a way to make this work? If I wanted to use something like tsc --rootDir ../.. to "fix" the working directory how would I know the level of depth to go up in the directory tree for the currently staged file?

Why would you want to use lint-staged for that? Just use husky pre-commit hook to run what ever command you need. It could be done using lint-staged && tsc-build-cmd. Note that tsc-build-cmd is not a valid command and needs to be substituted with the one which will build your project.

@sudo-suhas the reason would be that I only want to git add if compilation succeeded. tsc has many compilation checks and if it fails I wouldn't want it to git add. Also, I wouldn't want to compile before my linters have run.

Use the pre commit hook as I mentioned above. That will do what you need.

@sudo-suhas it would run git add even if compilation fails; no?

git add doesn't make any difference. You ran it before runninglint-staged anyway so effectively the files which were staged stay the same. What happens is that your pre-commit hook errors out during compilation and no commit is created. After that, it is upto you to modify required files, stage and commit them.

anyway to typecheck on lint-staged?

@sibelius I don't think TS supports that yet. Here is an example of how to do the check https://github.com/kubeapps/kubeapps/pull/700/files but it's not on staged files.

our use case for this is that we want typescript to compile our staged files - i.e. the commit. If we run it like lint-staged && tsc, then it will also attempt to compile unstaged changes.

Would you consider reopening this issue?

You can run tsc passing your tsconfig.json following these steps:

  1. Install eslint-plugin-tsc
  2. Do not add eslint-plugin-tsc to your eslint config file but instead pass the plugin to eslint in the lint-staged command as follows
{
  "*.ts": [
    "eslint --fix --plugin tsc --rule 'tsc/config: [2, {configFile: "./tsconfig.json"}]'",
    "git add"
  ]
}

If you are using husky, then you can do this:

// package.json
  "husky": {
    "hooks": {
      "pre-commit": "tsc --noEmit && lint-staged"
    }
  }

But it will check all .ts files of your project according to tsconfig.json instead of those staged files. May it help!

khose commented

@maoxiaoke tsc --noEmit won't do anything if you don't specify a file or the project setup file. Isn't it? When I try your solution, tsc does nothing.

@khose Do you have typescript as a peer dependency and a tsconfig.js file in the project root?

In your package.json.

...
"devDependencies": {
    "typescript": "^3.6.4"
}
...

In your tsconfig.json, you may specify which files you want to compile.

{
...
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx"
  ],
  "exclude": [
    "node_modules",
    "config"
  ]
}
khose commented

Hum, I don't have tsconfig.js in the root folder. The rest seems to be in place. Let me check and come back to you. Thanks @maoxiaoke !

szhu commented

hi, I know this is an already closed issue, but I still ran into it. I was able to fix it though!

I think the issue has nothing to do with tsconfig or the working directory. The issue is that lint-staged is appending the names of the changed files to the command. So if you're telling it to run tsc, it's actually running tsc changedfile1.ts changedfile2.ts. That's why it's ignoring your tsconfig, because passing extra files to it explicitly overrides that.

I fixed this issue with the following config:

  "lint-staged": {
     "*.ts": [
       "prettier --parser typescript --write --no-semi",
-      "tsc",
+      "bash -c tsc",
       "git add"
     ]
   },

bash doesn't automatically pass its args down to child commands -- bash -c tsc effectively runs tsc but ignores all args.

iiroj commented
szhu commented

Oh wow didn't see that, thanks!

iiroj commented

Np, youโ€™ll of course need to pass the first argument (array of filenames) to the other commands! You can see that in the other examples.

Anyone have a solution for running tsc type checking only on staged files and not on entire project? I looked through the thread but don't see any solution for this case.
Thanks!

Anyone have a solution for running tsc type checking only on staged files and not on entire project

That's not possible since TS needs to build the whole project in order to do type checking. This is the limitation of TypeScript. You should not probably do this in the pre-commit hook.

@uriklar you can run tsc as an eslint plugin (run one tool instead of many), using the mechanism I described here

Anyone have a solution for running tsc type checking only on staged files and not on entire project

That's not possible since TS needs to build the whole project in order to do type checking. This is the limitation of TypeScript. You should not probably do this in the pre-commit hook.

Wouldn't it be possible to have lint-staged call a function the user will provide (tsc in this case) during/after the Running tasks... section? With this we can make sure tsc only runs on the staged changes.

would it be posible to run a lint-staged cmd on pre-commit, like prettier and then run a different one that do a type check before pushing?. In my case I don't care about type checking before committing. Sometimes you can do WIP commits and you don't need to to run tsc there, but I do want to run it before pushing it to the repo.
I know there is a pre-push hook in husky but how can you run different lint-staged commands?

This might be useful, I have not tried it though https://github.com/gustavopch/tsc-files

For the most part, it just forwards all arguments to tsc with one exception: the specified files will not be forwarded โ€” instead, they will be put at the files property of a temporary config that will be generated next to your original tsconfig.json. Other than that, just read tsc --help.