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

Why --save instead of --save-dev? #81

Open
dalgard opened this Issue Jul 20, 2016 · 16 comments

Comments

Projects
None yet
10 participants
@dalgard
Copy link

dalgard commented Jul 20, 2016

In instructions on how to use @types, type packages are installed with --save and not --save-dev.

Why is this?

I wouldn't expect that I need the types outside of my development environment?

There should be a note about it in the various readmes.

@RyanCavanaugh

This comment has been minimized.

Copy link
Member

RyanCavanaugh commented Jul 20, 2016

@blakeembrey

This comment has been minimized.

Copy link

blakeembrey commented Jul 20, 2016

The short answer would be for module authors - if, as an author, you want to publish your TypeScript package to NPM and the dependencies are in the development section, no one will be able to install it and use it without having to manually install your types dev dependencies. By using dependencies, they will be installed along with the package and consumers can use your NPM package without additional configuration. The definitions should follow however you installed the module.

@DanielRosenwasser

This comment has been minimized.

Copy link
Member

DanielRosenwasser commented Jul 20, 2016

Using --save-dev is fine when you're writing a simple application, and it won't be used as a library. The problem comes along when you might have dependencies. If you stored your type declarations in your devDependencies, your consumers would not automatically get your type declarations. They'd then have to manually add your declaration file dependencies as their devDependencies.

Given that breaking consumers is a worse problem than slightly-larger packages, we've made --save the default in our documentation.

@unional

This comment has been minimized.

Copy link

unional commented Jul 20, 2016

If the types are exposed as dependencies, then it should be registered as dependencies. Otherwise, devDependencies.
But agree with @DanielRosenwasser that sometimes this distinction is not easy to make, especially for JS developer, so defaulting to dependencies is the better option.

@aluanhaddad

This comment has been minimized.

Copy link

aluanhaddad commented Oct 19, 2016

I've been basically taking the same road as @unional. Like I'll do
npm install --save-dev @types/tape
or
jspm install --dev npm:@types/tape 😛

@demurgos

This comment has been minimized.

Copy link

demurgos commented Oct 24, 2016

Hi,
I was trying to learn how to use @types so I looked trough the code of some some big projects using Typescript and none of them was using dependencies for @types:

Is this because these projects are special ? Angular is more front-end oriented and types-publisher is a standalone project (I think), but Typescript can be imported as a library and consumed by others: why aren't some of its @types normal dependencies (like node) ?

@DanielRosenwasser

This comment has been minimized.

Copy link
Member

DanielRosenwasser commented Oct 24, 2016

@demurgos With respect to TypeScript itself, it only uses declaration files for its build tools (like gulp utilities). It doesn't actually require those tools to run, so it doesn't need the declaration files for those tools either.

Edit: For the others, like Types Publisher, it doesn't matter what it's distributed as since it's a simple executable package that isn't meant to be used as a library.

@demurgos

This comment has been minimized.

Copy link

demurgos commented Oct 24, 2016

Thank you. So you mean that Typescript never require any of the Node's core libraries during runtime ? (outside of their tests/build process)

Basically, I am having trouble to know if I should install environmental types like @types/node as dependencies or devDependencies ? Should I list them as devDependencies and let the user provide them or should I list them as dependencies (and deal with #173) ?

@DanielRosenwasser

This comment has been minimized.

Copy link
Member

DanielRosenwasser commented Oct 24, 2016

My thought is dependencies since you're written as a library with dependents. For any users using Typings with TypeScript 1.8 and below, they shouldn't be affected, but as you noted, 2.0+ users may run into problems (at which point the solution is trivial - just remove node from their typings.json - but still annoying).

@ivogabe

This comment has been minimized.

Copy link

ivogabe commented Oct 25, 2016

Wouldn't that cause trouble when two dependencies depend on different version of @types/node? We're currently looking to use @types in gulp-typescript, and I'm afraid that this could cause issues for a lot of people, since the types of Node are polluting the global namespace. Basically there are two scenarios that could give issues: (1) a project depends on gulp-typescript (which depends on @types/node@1) and on @types/node@2, (2) a project depends on gulp-typescript (which depends on @types/node@1) and on foo, which depends on @types/node@2. NPM will install the types of node twice. Will this cause duplicate-identifier errors?

@andy-ms

This comment has been minimized.

Copy link
Member

andy-ms commented Oct 25, 2016

You could use a semver such as >= 4 to indicate compatibility with future node versions.

@JKillian

This comment has been minimized.

Copy link

JKillian commented Jan 12, 2017

Circling back to what @ivogabe asked - will TypeScript handle conflicting types in a way that works out okay? If I have packages depending on different versions of @types/react for example, can TS only apply those types where correct (based on their location in the node_modules tree? If it's not, it would be great to have a short write-up somewhere on the best way for library authors to include @types dependencies, I've heard a lot of questions about this from around my company.

@unional

This comment has been minimized.

Copy link

unional commented Jan 12, 2017

I have packages depending on different versions of @types/react for example, can TS only apply those types where correct (based on their location in the node_modules tree?

Add to that the even harder part is about module augmentation. Which version of react to augment?

@blakeembrey

This comment has been minimized.

Copy link

blakeembrey commented Jan 12, 2017

@JKillian I believe global definitions can and will conflict, while external module definitions follow module resolution. This is a bit of a pain point, because there's no guarantee a module in @types is external or global and that it won't change suddenly (lodash did this and generated a ton of build errors on various projects). I feel like there are better ways to solving this, but nothing that wouldn't break now.

@unional I think that one should be fine. You can kick in and use peerDependencies if you need to augment the parent. Type dependencies should mirror the regular dependencies for this reason.

@unional

This comment has been minimized.

Copy link

unional commented Jan 12, 2017

For react case, yes, because likely there are no direct dependency between react and the authoring package (e.g. react-redux).

But what if there is such a dependency? i.e.:

- app
  - package-a
    - package-b@2.0
  - package-c
    - package-b@1.0
  - package-b@??

And package-a and package-c both make an augmentation to package-b.

@inikulin inikulin referenced this issue Jan 11, 2018

Closed

Multiple environments support #235

17 of 17 tasks complete

@aomarks aomarks referenced this issue Jan 22, 2018

Merged

Refactor #67

@OliverJAsh OliverJAsh referenced this issue Jun 8, 2018

Merged

Initial PR #1

IlyaSemenov added a commit to ream/ream that referenced this issue Dec 3, 2018

feat: Typescript definitions
This adds certain @types/*** to package.json "dependencies".
The rationale is explained here:
Microsoft/types-publisher#81
@demurgos

This comment has been minimized.

Copy link

demurgos commented Jan 31, 2019

@DanielRosenwasser @RyanCavanaugh

Hi,
I am currently reevaluating how to handle @types/node: should it be in dependencies or devDependencies? With which ranges?

When I asked this question a few years ago, I got this reply (#81 (comment)):

My thought is dependencies since you're written as a library with dependents. For any users using Typings with TypeScript 1.8 and below, they shouldn't be affected, but as you noted, 2.0+ users may run into problems (at which point the solution is trivial - just remove node from their typings.json - but still annoying).

Despite this recommendation, there is still a lot of confusion around handling @types/node: read the issues referencing this discussion.

In my experience, adding @types/node to dependencies is the source of many compatibility issues: it is very easy to get incompatible duplicate definitions because it defines globals. Due to npm's dependency installation algorithm, you can get two (or more) different @type/node versions in your dependency tree.

My understanding is that type definitions declaring globals (e.g. @types/node, @types/mocha) should be treated as environment declarations, just like the lib field from tsconfig.json: es5, dom, es2015.promise, etc. This in turn means that they should only be defined by the top-level project.
Thus @type/node or any other global-inducing type definitions should be in devDependencies and never in dependencies. If a user wants to consume a lib depending on @types/node, he must explicitly provide it.
Since I started following this practice (for about 2 years now), I never had issues with duplicate global definitions again.

DefinitelyTyped adds @types/node to dependencies, but I am not sure if this is representative of how library providing their own types should be handled. The main difference is that DefinitelyTyped also owns @types/node: whenever types/node is updated, all the @types/* depending on it are updated. This means that they always use the exact same version. This is only possible because all these package live in the same repo. For individual projects, it is impossible to ensure that it always depends on the latest version of @types/node.

typings was less convenient but in regard to this issue it was a superior tool to npm+@types/ because it understood the difference between the different kinds of type declarations (ambiant/globals VS external module).

In 2019, how should a standalone Typescript library depend on environment/global declarations such as @types/node?

  • Using dependencies with a range x.y.z / ^x.y.z / >=x.y.z / *?
  • Using devDependencies with a range x.y.z / ^x.y.z / >=x.y.z / *?
  • Using peerDependencies with a range x.y.z / ^x.y.z / >=x.y.z / *?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment