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

Should tsc file.jsbuild a file with the "compilerOptions" in TypeScript's config. Or should it compile a file and ignore the config? #29241

Closed
EvanCarroll opened this issue Jan 3, 2019 · 44 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@EvanCarroll
Copy link

EvanCarroll commented Jan 3, 2019

With Node v11.6.0, and TSC, 3.2.2, I am getting

node_modules/rxjs/internal/Observable.d.ts:82:59 - error TS2585: 'Promise' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.                                                                   

82     toPromise<T>(this: Observable<T>, PromiseCtor: typeof Promise): Promise<T>;                                                                    
                                                             ~~~~~~~


Found 1 error.

When I run

type P = typeof Promise;

Using @types/node

This is a bug push up from rxjs ReactiveX/rxjs#4448
You can see the issue documented at https://stackoverflow.com/questions/54014405/ts2585-promise-only-refers-to-a-type-but-is-being-used-as-a-value-here

@fatcerberus
Copy link

The error message says you should be targeting lib: "es2015”. Are you? Note that lib and target are distinct because of polyfills (you can polyfill builtins but not syntax)

@EvanCarroll
Copy link
Author

EvanCarroll commented Jan 3, 2019

@fatcerberus I have a sample repo with it, in that repo i'm doing es2018 for lib, but you can try es2015 same thing.

https://github.com/EvanCarroll/rxjsissue4448

@fatcerberus
Copy link

Just a hunch, have you tried using lowercase for es2018? I know the docs show uppercase but I think that might be a mistake as I’ve always seen it lowercase in practice. Otherwise I have no clue what’s wrong here, it seems bizarre.

@EvanCarroll
Copy link
Author

It is lower case, no joy. It's also confirmed by the rxjs guys and the stackoverflow commenter. Nothing that uses promises works on node 11

@fatcerberus
Copy link

fatcerberus commented Jan 3, 2019

What I don’t understand is what the node version has to do with this - typescript and node are completely separate tools.

oh okay - I see, the issue is when the typescript compiler is run on node 11, not when targeting node 11. My bad.

@fatcerberus
Copy link

So I tried to reproduce this using the exact tsconfig, dependencies, and sample code as in the SO question... and it seems to work fine on my end. Node.js version is 11.6.0.

npm install typescript
npm install rxjs
npm install @types/node
npm install ts-node
D:\temp>npx tsc

D:\temp>type main.js
import { range } from 'rxjs';
import { map, filter } from 'rxjs/operators';
range(1, 200).pipe(filter(x => x % 2 === 1), map(x => x + x)).subscribe(x => console.log(x));

@EvanCarroll
Copy link
Author

EvanCarroll commented Jan 3, 2019

Did you pull down my repository run npm install and then try to tsc the file? I'm confused, you say this

oh okay - I see, the issue is when the typescript compiler is run on node 11

Which is true, and then you say " it seems to work fine on my end. Node.js version is 11.6.0."

@fatcerberus
Copy link

Yeah, that was before I tested it - that was just stating I understood why you mentioned the node version.

@EvanCarroll
Copy link
Author

EvanCarroll commented Jan 3, 2019

I don't know what else to say, I got the prob. Guy on SO and on RXJS question got the prob. Repo is simple works (to show the problem) with the latest version of all tools. It's giving that error on running tsc on my box (running Linux).

@EvanCarroll
Copy link
Author

This is the line that's problematic for you, this is working?

type P = typeof Promise;

@fatcerberus
Copy link

fatcerberus commented Jan 3, 2019

Yeah, that works, as does:

C:\temp>git clone https://github.com/EvanCarroll/rxjsissue4448
Cloning into 'rxjsissue4448'...
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 6 (delta 0), reused 6 (delta 0), pack-reused 0
Unpacking objects: 100% (6/6), done.

C:\temp>cd rxjsissue4448

C:\temp\rxjsissue4448>npm install
npm WARN foo@1.0.0 No description
npm WARN foo@1.0.0 No repository field.

added 3 packages from 39 contributors and audited 3 packages in 1.825s
found 0 vulnerabilities


C:\temp\rxjsissue4448>npx tsc

C:\temp\rxjsissue4448>node -v
v11.5.0

v11.5 because I switched machines--still Node 11 though. Tested on both Windows and Linux (Ubuntu 16.04, Node.js installed from snap).

Only thing I can think of is you're somehow picking up a stale tsconfig.json from elsewhere.

@EvanCarroll
Copy link
Author

no idea what npx does, or what it's doing differently can you just run tsc runme.tsc?

@fatcerberus
Copy link

fatcerberus commented Jan 3, 2019

It's the same thing - tsc by itself requires typescript installed globally, npx is when it's installed locally (in node_modules). Works either way.

@EvanCarroll
Copy link
Author

No idea, all I know is it's erroring with me and I'm not using any special layer so I'm trying to keep it simple and figure out why it's not erroring for you, and I'm thinking your npx is doing something.

@fatcerberus
Copy link

fatcerberus commented Jan 3, 2019

tsc runme.ts

Nope, here's the exact issue - you're telling tsc to transpile a single file. In that case it ignores the tsconfig.json and just transpiles the file in a vacuum, using all defaults for the tsconfig fields. Since there is no ///<reference> tag in the source for the es2015 lib you get the Promise error.

@fatcerberus
Copy link

What you want to do is just run tsc. You can include/exclude files as necessary by specifying them in the tsconfig (which is your project file).

@fatcerberus
Copy link

This behavior, by the way, is documented:
https://www.typescriptlang.org/docs/handbook/tsconfig-json.html

When input files are specified on the command line, tsconfig.json files are ignored.

@EvanCarroll
Copy link
Author

EvanCarroll commented Jan 3, 2019

Nope, here's the exact issue - you're telling tsc to transpile a single file. In that case it ignores the tsconfig.json and just transpiles the file in a vacuum, using all defaults for the tsconfig fields. Since there is no /// tag in the source for the es2015 lib you get the Promise error.

Wow, even if documented that's extremely counter intuitive. I can't think of any program that ignores the configuration file when given an argument that isn't explicitly either conflicting with the configuration file, or demanding to override it. That's not a good user interface at all. Git and NPM being two examples that don't behave in that way that typescript users are likely to be using in the same project.

@EvanCarroll
Copy link
Author

EvanCarroll commented Jan 3, 2019

The use case here being

  1. that a project needs Typescript so they install it.
  2. they run tsc file.ts which they believe runs Typescript on the file.
  3. they get an error
  4. They google the error
  5. The error is remedied by adding something to their typescript config.
  6. They do that and run tsc file.ts again and get the same error

At the absolute least I would expect tsc to be verbose by default and tell us it's ignoring the configuartion file which specifies the values of lib needed. I imagine many of your users are doing the above. I use TSC regularly but I've never used it with Rx.js outside of a project that had tsc. So now I'm just wanting to use tsc for Rx.js.

@fatcerberus
Copy link

It makes sense to me at least - you either tell it to compile a whole project file, or you pass one or more source files and specify the options on the command line. Everything you can specify in tsconfig.json has a corresponding command-line option.

It would be probably be bad if it used the tsconfig when specifying files on the command line - since then if you used tsc in, say, a shell script, the behavior of the script would change depending on whether the CWD contained a tsconfig.

@fatcerberus
Copy link

Essentially the tsconfig is a “build script” - you tell tsc to use that instead of specifying everything you want to do on the command line. It’s not a “compiler preferences” file (admittedly the naming of “tsconfig” is a bit confusing in that regard), it’s a self-contained project in itself, like what .vcproj is for MSVC.

@fatcerberus
Copy link

Basically: think of tsconfig.json as a makefile, and tsc as a make tool + compiler in one.

@EvanCarroll
Copy link
Author

EvanCarroll commented Jan 3, 2019

since then if you used tsc in, say, a shell script, the behavior of the script would change depending on whether the CWD contained a tsconfig.

Isn't that how everything works though?

  • make reads .Makefile in the current directory
  • npm reads package.json in the current directory
  • git reads .gitignore in the current directory

None of them forget about their config file when you provide an option. They simply override that option and use the config file to create the execution environment for the command. I understand what you're talking about but this is the only utility that works in this fashion -- where providing an argument means it forgets about the config file.

I want the config file to configure TSC for the project. Not to specify the exact item i'm wanting to compile. It just intuitive to me that the working directory be significant, especially if there is a config file inside it and not only if there are no arguments provided to the program.

@fatcerberus
Copy link

Let me make it clear: What you’re essentially asking for is analogous to wanting gcc to honor options in a makefile even when invoked directly. It just so happens that tsc combines these two functions into one program.

@fatcerberus
Copy link

What you may be able to do is (not tested):

tsc --project ./tsconfig.json runme.ts

@EvanCarroll
Copy link
Author

EvanCarroll commented Jan 3, 2019

Let me make it clear: What you’re essentially asking for is analogous to wanting gcc to honor options in a makefile even when invoked directly. It just so happens that tsc combines these two functions into one program.

Not exactly, because GCC and make are separate; there is a distinction there so I would never expect gcc to accept a configuration file anyway. But tsc does with the --project command you've provided which makes it similar to make, and npm, and git.

So with make if you have a basic Makefile,

.PHONY: ALL                                                                                                                                            
                                                                                                                                                       
CFLAGS="COMPILER FLAGS"                                                                                                                                
                                                                                                                                                       
ALL: foo bar                                                                                                                                           
                                                                                                                                                       
.DEFAULT:                                                                                                                                                     
  @echo "${CFLAGS}" caught target $@    

And you run make it builds foo and bar, now if you run

make baz

It still uses the make file. It doesn't forget it and act like a compiler. It just builds instead baz. And it does it with the CFLAGS. The same applies btw if you want to run one specific rule or compile one file outside. For example if you run make foo.c inside of a build directory it will use the Makefile to build that one file.

@EvanCarroll
Copy link
Author

Does it seem intuitive to you to say that the default for --project is ./tsconfig.json in all instances except when you provide it arguments? In which case if you want to use tsconfig.json you have to manually supply it?

@fatcerberus
Copy link

fatcerberus commented Jan 3, 2019

Using the above analogy:
tsc file.ts is gcc.
tsc --project is make.

It just so happens that, for convenience, the specific case of tsc with no arguments implies --project. The alternative would be an error because you didn’t provide any input files.

@EvanCarroll
Copy link
Author

EvanCarroll commented Jan 3, 2019

I understand how things are, now that you've explained them and did immediately on my first response here. I just find that entirely unintuitive and I imagine I'm in the majority here. You've severed tsc into two modes, neither of which are apparent to the user and used those two modes to justify a different user interface. I wasn't aware that I was supposed to

  • think of tsc file.ts as a compiler
  • tsc as a make system
  • the file ./tsconfig.json as a default configuration for the make system, but also an acceptable and optional configuration file for the compiler environment via --project
  • think of tsc file.ts as an invocation of the compiler, rather than tsc file.ts as being a directive to build the file with the configuration file.

I'll just leave it off with this, because I'm honestly just trying to provide some guidance to build a better system. Ask some people who do NOT know the default behavior this question

"If tsc builds a project by reading from tsconfig.json, would you expect tsc file.ts to build that file with the configuration in tsconfig.json, or to ignore tsconfig.json and compile the file?"

Just for fun https://twitter.com/TheEvanCarroll/status/1080899909522477061 (maybe I am in the minority)

@fatcerberus
Copy link

fatcerberus commented Jan 3, 2019

I’ll agree with you that the “project builder” should probably be a separate tool (tsmake or something), but practically speaking, since I assume it was a conscious design decision not to have two distinct tools, how would you make tsc fully scriptable like a command line compiler (without the risk of picking up stray config files—just look to eslint for how many headaches that can cause) but still get the make-like functionality? Given those constraints, I would probably set up things up the same way.

@ljharb
Copy link
Contributor

ljharb commented Jan 3, 2019

Wouldn't you want to follow the lead of most all the other tools (eslint, babel, etc) and have an explicit CLI opt-out for avoiding the config file? In other words, "gcc" usage is nowhere near the common case, and seems surprising to most users, so it seems like a poor choice of default.

@fatcerberus
Copy link

In any case, I don’t think this can be changed now without breaking peoples’ build environments, which would be bad considering how TypeScript’s release cycle seems to work (every major or minor version supersedes the last). But I’ll duck out at this point and let actual TypeScript team members chime in if they want before I accidentally make a fool of myself. 😄

@weswigham weswigham added Question An issue which isn't directly actionable in code Discussion Issues which may not have code impact labels Jan 3, 2019
@denis-sokolov
Copy link

Would you consider changing the title of the issue to better reflect the ongoing conversation, to provide a better summary and be more convenient to find? For an example, “Inconsistent tsc behavior with and without file parameters”. @EvanCarroll @weswigham

@EvanCarroll EvanCarroll changed the title TS2585: 'Promise' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing the lib compiler option to es2015 or later Should tsc file.jsbuild a file with the "compilerOptions" in TypeScript's config. Or should it compile a file and ignore the config? Jan 4, 2019
@timocov
Copy link
Contributor

timocov commented Feb 1, 2019

Another use case: we have a pre-commit hook which runs tsc for all changed files, and as soon we can't mix --project with files list we wrote a code to convert compilerOptions to CLI args. Everything works fine until today when we want to use paths compiler option, which cannot be passed via CLI 😞

Even without implicit using tsconfig.json for compiler options why we can't use --project arg and files list together?

(maybe this isn't that issue where I should post this comment, but my opinion is that tsc should use compiler options from a config while compiling only one file)

@kinowarrior
Copy link

Thanks for your help all. Problem solved here.

@typescript-bot
Copy link
Collaborator

This issue has been marked as 'Question' and has seen no recent activity. It has been automatically closed for house-keeping purposes. If you're still waiting on a response, questions are usually better suited to stackoverflow.

@chrisblossom
Copy link

@DanielRosenwasser @RyanCavanaugh It is very disappointing this hasn't been taken further into consideration. This is how 98% of javascript developers expect tsc to behave and would make tsc consistent with every other node tool out there.

@ljharb
Copy link
Contributor

ljharb commented Jul 13, 2019

Please reopen; nonhumans closing issues is exceedingly user-hostile.

@0vidiu
Copy link

0vidiu commented Aug 6, 2019

Allowing to override tsconfig.json by passing a file path with tsc --noEmit -p tsconfig.json would be really useful and would avoid having multiple config files. Please reopen. Thank you!

@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented Aug 6, 2019

Allowing to override tsconfig.json by passing a file path with tsc --noEmit -p tsconfig.json would be really useful and would avoid having multiple config files. Please reopen. Thank you!

This is already supported!

Please reopen; nonhumans closing issues is exceedingly user-hostile.

I will close this myself to help 😉

@RyanCavanaugh
Copy link
Member

This is the intended behavior because we don't want to break thousands of msbuild-based compilations where people are using .csproj settings for one compilation and tsconfig.json for something else. Even issuing a warning when a tsconfig.json is present has the potential to break these builds because people might have warnings-as-errors turned on.

@timocov
Copy link
Contributor

timocov commented Aug 6, 2019

people are using .csproj settings for one compilation and tsconfig.json for something else

You can add --no-project flag for them (it's joke, don't bear on me 🙂).

Even issuing a warning when a tsconfig.json is present has the potential to break these builds because people might have warnings-as-errors turned on.

What about allowing to pass a list of files along with --project to override files to compile? It seems that it shouldn't break case you've described above.

Also, what's about compiler options which cannot be passed via CLI such paths (see #29241 (comment))?

@RyanCavanaugh

@RyanCavanaugh
Copy link
Member

What about allowing to pass a list of files along with --project to override files to compile?

See also #27379. I think there's also another issue where people expect to be able to augment the file list in this manner.

Also, what's about compiler options which cannot be passed via CLI

I think allowing some way of specifying additional tsconfig files (probably in a "config only" mode) would be a very reasonable suggestion. I know some teams are effectively doing this by auto-generating tsconfig files in their build scripts; it'd be nice to make that kind of automation unnecessary.

@0vidiu
Copy link

0vidiu commented Aug 8, 2019

What about allowing to pass a list of files along with --project to override files to compile? It seems that it shouldn't break case you've described above.

Also, what's about compiler options which cannot be passed via CLI such paths (see #29241 (comment))?

This is exactly what I was trying to do and it doesn't work for me. I will look at versions for a new update if you're saying this is supported already.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests