Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow tsconfig.json when input files are specified #27379

Open
brapifra opened this issue Sep 26, 2018 · 36 comments · May be fixed by #49817
Open

Allow tsconfig.json when input files are specified #27379

brapifra opened this issue Sep 26, 2018 · 36 comments · May be fixed by #49817
Labels
In Discussion Not yet reached consensus Suggestion An idea for TypeScript

Comments

@brapifra
Copy link

brapifra commented Sep 26, 2018

I don't know why the tsconfig.json is ignored even when the --project or -p option is specified.
In my opinion, the right implementation should be:

  • If no --project or -p option: Ignore tsconfig.json
  • Otherwise: Use the configuration file specified. All the options used in the command line should overwrite the ones of the configuration file. E.g. The include/exclude keys of the tsconfig.json will be ignored when input files are specified.
@andy-ms
Copy link
Contributor

andy-ms commented Sep 26, 2018

I don't know why the tsconfig.json is ignored even when the --project or -p option is specified.

Could you provide a repro for a situation where tsconfig is ignored?

@andy-ms andy-ms added the Needs More Info The issue still hasn't been fully clarified label Sep 26, 2018
@brapifra
Copy link
Author

brapifra commented Sep 26, 2018

Sure @andy-ms , but I mean, this is not even a bug. This behaviour is explicitly explained in the docs: When input files are specified on the command line, tsconfig.json files are ignored.

When you do tsc file.ts -p tsconfig.json you get:
captura de pantalla de 2018-09-26 22-34-25

The lines of code are pretty easy to find

I just can't understand why it's implemented this way.

@andy-ms
Copy link
Contributor

andy-ms commented Sep 26, 2018

Probably because no one's implemented it -- could you explain what the use cases are?

@andy-ms andy-ms added Suggestion An idea for TypeScript and removed Needs More Info The issue still hasn't been fully clarified labels Sep 26, 2018
@brapifra
Copy link
Author

brapifra commented Sep 27, 2018

A pretty common practice is to have a pre-commit hook to compile only the staged files in your git project (It makes no sense to compile all the project).
If you try to create this hook that runs tsc over each staged file, you won't be able to use the tsconfig.json, as you are specifying some input files. @andy-ms

@weswigham weswigham added the In Discussion Not yet reached consensus label Nov 6, 2018
@jescalan
Copy link

jescalan commented Feb 14, 2019

I have another use case for this. We have many projects that use typescript, and would like to reduce boilerplate and keep our typescript config in one place, so it can be uniformly applied across all our projects for consistency.

At the moment, there isn't a way to do this, since you can't specify both a glob of files to check, and an external path to a tsconfig.json file. The only workaround in the meantime is to copy/paste a tsconfig.json file into the root of every project and have it only contain an "extends" statement. This isn't the end of the world, but it's more boilerplate than we want - the fewer duplicate files across multiple projects we can have, the better.

This same goal is easily accomplished with TSLint, by using their --config option as well as a glob of files to lint. Is there any specific reason why it is disallowed by typescript itself? If not, I would be happy to take a stab at implementing it via pull request, just want to make sure its ok with maintainers.

@zpdDG4gta8XKpMCd
Copy link

zpdDG4gta8XKpMCd commented Apr 2, 2019

related, but never considered #12958

@RyanCavanaugh RyanCavanaugh added Needs Investigation This issue needs a team member to investigate its status. and removed In Discussion Not yet reached consensus labels Apr 2, 2019
@RyanCavanaugh RyanCavanaugh self-assigned this Apr 2, 2019
@JasonKaz
Copy link

JasonKaz commented May 25, 2019

I have a different use case that needs this as well. We have a pre-commit hook that does a quick type check (tsc -p tsconfig.json --noEmit). Currently it checks all the files specified in tsconfig.json, but it would be nice to only type check the files that were modified. We are currently using lint-staged to run linting tools on modified files, it would be great to only run the type check on the modified files too.

Like @brapifra said here, #27379 (comment), it's written in the docs that this should be possible, but it clearly isn't.

@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented Aug 21, 2019

ref #22649, #13575

@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented Aug 21, 2019

We have some questions for everyone in this thread

Long story short, the real problem we see is that people make a tsconfig.json, then run

tsc someFile.ts

and get garbage confusing errors because e.g. their tsconfig specifies target: ESNext and the error says something like "This is an ES5+ only API, change your target!". So we'd like to change that so that tsc always picks up a nearby tsconfig file, and provide an opt-out like --ignore-tsconfig for people who want to ignore it intentionally.

However, we're not sure what tsc someFile.ts means if there's a tsconfig present:

Question 1, do we:

  • Overwrite the files setting
  • Append to the files setting
  • Prepend to the files setting (order rarely matters but sometimes does...)

Question 2:

  • Are include and exclude still in play if there are some files specified on the commandline?

Question 3:

  • What if someFile.ts was in the exclude list?

Thoughts?

@RyanCavanaugh RyanCavanaugh added In Discussion Not yet reached consensus and removed Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature labels Aug 21, 2019
@fatcerberus
Copy link

fatcerberus commented Aug 21, 2019

Just my two cents:

A pretty common practice is to have a pre-commit hook to compile only the staged files in your git project (It makes no sense to compile all the project).

This use case seems problematic in general, since (AFAIK) TS needs to see your whole project for some things to work (e.g. const enum, declaration merging), unless you use isolatedModules which disables those features.

@timocov
Copy link
Contributor

timocov commented Aug 22, 2019

Question 1.

I would expect that we'll "Overwrite the files setting".

Question 3.

If we'll treat someFile.ts as file to override files list, then no problem here - from the docs:

Files included using "include" can be filtered using the "exclude" property. However, files included explicitly using the "files" property are always included regardless of "exclude".

Question 2.

IMO include should be ignored in this case.

I think there is cases when some modules pollute global scope and it might break the compilation (because not all modules require that modules with globals even if they use them), but I believe developers should import deps explicitly (via triple-slash directives or even import statements in this case).

@timocov
Copy link
Contributor

timocov commented Aug 22, 2019

So we'd like to change that so that tsc always picks up a nearby tsconfig file, and provide an opt-out like --ignore-tsconfig for people who want to ignore it intentionally.

@RyanCavanaugh So, we will not be able to pass path to the custom tsconfig via --project CLI option, right? I believe it's a use case as well and it would be good to cover it too.

@msbit
Copy link

msbit commented Aug 30, 2020

Adding to the responses to the questions:

Question 1

  • Overwrite the files setting

Question 2

  • Ignore the include and exclude settings if files are specified on the commandline

Question 3

  • Not applicable due to answer to Question 2

@gomesalexandre
Copy link

gomesalexandre commented Dec 11, 2020

We would find value in this for writing an arcanist tsc linter.

Please find below the use-case and workaround in case you need it

The way arcanist external linters work is by specifying an includes regex and then running your linter on every file that matches it. Tried pretty much everything, unfortunately, right now the only way to make tsc <file> type-checking work and handle tsconfig.json seems to write a runner (a.k.a tsc spawner). It works by:

  • specifying it to arcanist as the only file to type check in .arclint
  • implementing an ArcanistExternalLinter whose sole responsibility is to call node runner.js
  • runner will be called back as node <runnerPath/runner.js> <projectRoot> <runnerPath/runner.js>
  • on runner.js, parse args and execute a spawn of tsc from project root, to type the whole codebase

This way, tsc is called once, type-checks the whole codebase and handles tsconfig.json as it should.

.arclint

{
  "linters": {
    "tsc": {
      "type": "tsc",
      // will call back linter just once, because we include just one file
      // it could be any existing file in filesystem, it doesn't matter
      "include": "/^linters\\/arc-tsclint\\/lint\\/linter\\/runner\\.js$/"
    }
  }
}

linters/tsc/lint/linter/runner.js

function main() {
  // We don't end up using currentFile, refactor when 27379 is fixed
  const [, , projectRoot, currentFile] = process.argv;

  const { stderr, stdout, status } = spawnSync("tsc", ["--noEmit", "--jsx", "react"], {
    cwd: projectRoot,
  });
  // Do arcanist-related stuff with stderr stdout and status
}

Overall a similar use-case as the one @brapifra noted, and we would like not to be reliant on such a hack.

@Envek
Copy link

Envek commented Dec 11, 2020

One more use-case is serverless Lambda functions.

It is convenient to have many related Lambda functions together in one project with common tsconfig.js and common reused utility code reused by some but not all functions. Given that every Lambda function has only one entry point – its handler – we can compile only this handler file and will get only files required to run this given Lambda function.

This not only allows to put less files into function's code, but (which is more important) to update only those functions that really uses changed code.

Example

Given following project structure:

── src
    ├── handlers
    │   ├── a.ts
    │   ├── b.ts
    │   └── c.ts
    └── utils
        ├── ab.js
        └── bc.js

By executing following comands:

tsc --project . --outDir .aws-sam/build/AFunction src/handlers/a.ts
tsc --project . --outDir .aws-sam/build/BFunction src/handlers/b.ts
tsc --project . --outDir .aws-sam/build/CFunction src/handlers/c.ts

I want to get following transpiled results that uses settings from tsconfig.json:

.aws-sam/build/AFunction
└── src
    ├── handlers
    │   └── a.js
    └── utils
        └── ac.js
.aws-sam/build/AFunction
└── src
    ├── handlers
    │   └── b.js
    └── utils
        ├── ab.js
        └── bc.js
.aws-sam/build/CFunction
└── src
    ├── handlers
    │   └── c.js
    └── utils
        └── bc.js

Workaround

Generate one-off child tsconfig files that overwrites includes property as described at https://stackoverflow.com/a/44748041

echo "{\"extends\": \"./tsconfig.json\", \"include\": [\"src/handlers/a.ts\"] }" > tsconfig-only-handler-a.json
tsc --build tsconfig-only-handler-a.json

Envek added a commit to Envek/aws-sam-typescript-layers-example that referenced this issue Dec 14, 2020
**Problem**

When we change code for only one of Lambda functions, we have to update all of them on `sam deploy` because every function contains all of JS files no matter whether they are being used by this particular function or not.

**Solution**

We can use the fact that when TypeScript compiler is given path to single file, it will only compile this file and all its dependencies. Given that every Lambda function has handler–an entry point–we can compile only this handler and will get only files required to run this given Lambda.

To make TSC honor our configuration from `tsconfig.json` the hack with child tsconfig file is needed: https://stackoverflow.com/a/44748041 (see microsoft/TypeScript#27379 (comment) for details)
Envek added a commit to Envek/aws-sam-typescript-layers-example that referenced this issue Dec 14, 2020
**Problem**

When we change code for only one of Lambda functions, we have to update all of them on `sam deploy` because every function contains all of JS files no matter whether they are being used by this particular function or not.

**Solution**

We can use the fact that when TypeScript compiler is given path to single file, it will only compile this file and all its dependencies. Given that every Lambda function has handler–an entry point–we can compile only this handler and will get only files required to run this given Lambda.

To make TSC honor our configuration from `tsconfig.json` the hack with child tsconfig file is needed: https://stackoverflow.com/a/44748041 (see microsoft/TypeScript#27379 (comment) for details)
@EddyVinck
Copy link

EddyVinck commented Jul 20, 2021

As https://github.com/AkhmadBabaev mentioned here #27379 (comment)

This worked for my project:

  • tsconfig.json in project root
  • use lint-staged.config.js
  • omit -p tsconfig.json from tsc command
// lint-staged.config.js
module.exports = {
  "*.{js,ts,tsx}": "eslint --cache --fix",
  "**/*.ts?(x)": () => "tsc --noEmit",
};

@loynoir
Copy link

loynoir commented Aug 1, 2021

I end up with esbuild so far.

@loynoir
Copy link

loynoir commented Aug 1, 2021

npx esbuild ./config/*config.ts  \
    --tsconfig=./config/tsconfig.esm.json \
    --outdir=./config-out \
    --format=esm \
    --out-extension:.js=.mjs \
    --watch

@rattrayalex
Copy link

rattrayalex commented Sep 10, 2021

My use-case is that we have converted a messy JS codebase to TS, so there are thousands of type errors. We want to go through and clean them up gradually, over time.

This means that we can't fail the build in CI for errors running tsc for the whole project.

It also means that running tsc --watch to diagnose and fix errors is pretty useless, you have to scroll through a bunch of errors unrelated to what you're working on.

I would love to be able to run a command like tsc --focus foo.ts bar.ts which will only show errors that occur in foo.ts or bar.ts (not even related errors in other files) – literally just filter the output of tsc by filepath.

@cwilso03
Copy link

cwilso03 commented Dec 22, 2021

My use-case has to do with Jest tests or npm run utility scripts invoked using ts-node. In my tsconfig.json I have some non-default compiler options set (e.g., "strict": true, "target": "ES2021", etc.), as well as the use of a dist output directory for the compiled JavaScript. When Jest tests or ts-node runs a single .ts file, it compiles with different options (i.e., the default options) than I have specified, and, worse, pollutes my src/** directory with a bunch of individual .js files (since, by default, the TypeScript compiler outputs the .js alongside the .ts source).

In my opinion, if a project takes the effort to define a project-wide tsconfig.json, those settings should be used whenever tsc is invoked. Command-line options to tsc at that point can/should override any conflicting setting in tsconfig.json.

@dfabulich
Copy link

dfabulich commented Aug 24, 2022

This issue has hundreds of 👍 responses. In #27379 (comment) @RyanCavanaugh asked important questions about how it should work. In #27379 (comment) @timocov answered those questions, ("overwrite files setting") and got 9 👍 emojis and no negative responses. There was another response #27379 (comment) from @moopmonster which gave the exact same answer, and got 24 👍 emojis.

@RyanCavanaugh's question appears to be settled.

I speculate that a PR would be welcome that simply implemented the "overwrite files" approach.

garthendrich added a commit to garthendrich/Memrize that referenced this issue Aug 31, 2022
This will use an ESM format config file for Lint-staged to allow use of functions. A function is needed for the Typescript CLI to follow the tsconfig (microsoft/TypeScript#27379 (comment)).

The commands in an array will be executed one after another. This will prevent conflicts of a race condition.
@moonformeli
Copy link

moonformeli commented Oct 13, 2022

It will be really nice if TypeScript team puts time on this issue.
I've read TypeScript's tsconfig.json behavior, it says TypeScript tries to seek every relative file that imports "ns" if you import "ns" as below.

import * ns from "mod"

And if the TS compiler finds files which import "ns", it automatically includes them in its compiling even though you don't want them to be type-checked. So to me, it sounds like TS will eventually look at extra files which might not be the ones you modified.

We want the option to tell the compiler to check the specific files, about TS grammar only, Not checking every referencing file! 😱

@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented Oct 13, 2022

@moonformeli

We want the option to tell the compiler to check the specific files

This exists and is called noResolve

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
In Discussion Not yet reached consensus Suggestion An idea for TypeScript
Projects
Development

Successfully merging a pull request may close this issue.