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

Typescript should follow semantic versioning #14116

Closed
jbgraug opened this issue Feb 16, 2017 · 37 comments
Closed

Typescript should follow semantic versioning #14116

jbgraug opened this issue Feb 16, 2017 · 37 comments

Comments

@jbgraug
Copy link

@jbgraug jbgraug commented Feb 16, 2017

I guess this can be considered as a bug as it is breaking my apps.
If version 2.1.0 has breaking changes, why don't set it to 3.0.0? Semantic versioning, right?
Typescript lives and has important role in the nodejs ecosystem, therefore should follow some basic rules.
We can not use the npm's semver features to block only major changes.

TypeScript Version: 2.1.1 / nightly (2.2.0-dev.201xxxxx)

2.1.0
Code

// A *self-contained* demonstration of the problem follows...
No need

Expected behavior:
Follow semantic versioning rules
Actual behavior:
Just follows marketing versioning rules
can be related to #6520 created a year ago and closed without being solved

@mhegazy
Copy link
Contributor

@mhegazy mhegazy commented Feb 16, 2017

TypeScript never claimed to follow semantic versioning, in the sense that breaking changes imply major versions.

TypeScript, however, promises no breaking changes after a stable release. so no breaking changes between 2.1.5 and 2.1.6, 2.1.*.

My recommendation is fix your version of typescript to major.minor instead of just major. e.g. ^2.1 and not ^2

@jbgraug
Copy link
Author

@jbgraug jbgraug commented Feb 17, 2017

Thanks for the early response @mhegazy .
As you mentioned, blocking the versions is easy to fix in my projects (I was being a bit ironic.).
However, as a developer i don't feel comfortable having to memorise a different set of rules for each package as the number of packages used grows very quickly.
I guess having typescript follow semantic versioning would be a nice to have feature.

@RyanCavanaugh
Copy link
Member

@RyanCavanaugh RyanCavanaugh commented Feb 17, 2017

The trade-off for getting millions of dollars of engineering investment in the TypeScript project is that marketing gets to control version numbers to a certain extent.

It's not really an unalloyed good anyway. If we followed semver rules exactly, literally every single release would be a major version bump. Any time we produced the wrong type or emitted the wrong code or failed to issue a correct error, that's a breaking change, and we fix dozens of bugs like that in every release. The middle digit just isn't useful for TypeScript in a strict semver interpretation.

@niieani
Copy link

@niieani niieani commented Feb 19, 2017

NPM should simply allow for descriptive marketing versions as a forth group. Then we'd have the best of both worlds, i.e.

       marketing
           
TypeScript 2.34.2.1 
             ∧∧ ∧ ∧
          major ∧ patch
                
              minor

You would simply skip the marketing version while installing, i.e. npm install typescript@^34 since it would hold no semantic meaning, i.e. bumping marketing wouldn't reset the major counter.

@BenSayers
Copy link

@BenSayers BenSayers commented Apr 7, 2017

I'm concerned that not following semver is creating unnecessary friction for TypeScript consumers who are opted in to having their builds broken whenever TypeScript releases a minor version as npm locks down to only major versions by default. The Microsoft Edge team has figured out how to do their marketing despite bumping the major version a few times a month (currently up to v38), I think TypeScript should give serious consideration to doing the same for the good of its consumers.

@aluanhaddad
Copy link
Contributor

@aluanhaddad aluanhaddad commented Apr 7, 2017

Personally, I think it is a good idea to always specify exact versions of critical stack components such as compilers, loaders, bundlers, and of course frameworks.

There are not that many of these tools in a single project and they do not tend to release more than once a week or so. This makes explicitly upgrading a relatively straightforward process.

Also, reading the changelogs for updates to such key dependencies is almost certainly something that one should be doing.

That said, I think it's fine to version more liberally. Each project is different in this regard.

The trade-off for getting millions of dollars of engineering investment in the TypeScript project is that marketing gets to control version numbers to a certain extent.

That is a trade well worth making.

Furthermore, TypeScript is by no means the only project that does this.

I think any project that is high profile enough is likely subject to this, at least to some extent.

Even if it is not the marketing department, it may be the maintainers' own self-consciousness that leads to such versioning.

Any time we produced the wrong type or emitted the wrong code or failed to issue a correct error, that's a breaking change, and we fix dozens of bugs like that in every release.

TypeScript really releases at a blisteringly unprecedented pace for a programming language so I think this is somewhat inevitable. I also think it's common across almost all software. Minor versions of most software contain breaking changes, but they often go unnoticed. The more high-profile the project, the more users that has, the more likely it is that this will be noticed.

The TypeScript team do an incredible job and they ship a wonderfully high quality product.

@gcnew
Copy link
Contributor

@gcnew gcnew commented Apr 7, 2017

I can't agree with @aluanhaddad more. Personally, I think using language version 81 and browser version 127 is terrible. It looks ugly and these high numbers quickly become meaningless. In the browser case that's the intention - forcing consumers to update to the latest version. However, for a language it's out of place and makes following new features and important changes extremely hard. Every version, no matter how big or small, looks the same way as every other. Flow has fallen in that trap and it doesn't seem to reap many benefits out of it.

For TypeScript, if you still want automatic updates without worrying too much, just lock the minor version in and everything will fall into place.

@RyanCavanaugh
Copy link
Member

@RyanCavanaugh RyanCavanaugh commented Apr 7, 2017

I mean, even semver's own definition of "breaking change" is arguably wrong. Minor updates can add new functionality under new properties, and new properties can break existing codepaths because JS is full of do-x-if-y-property-is-present patterns. Fixing a performance bug, which would in theory be a bugfix version update, could cause two async operations which previously always resolved in one order to instead always resolve in another order.

It is simply not the case that you can safely upgrade code, with semver as used today by normal package maintainers, from 34.1 of some library to 34.9 and be guaranteed that your program will still behave the same way.

What semver means in practice is that the major version bump is "You will probably need to update your code in a lot of places", and the minor version bump is "You should always be OK for the most part". TypeScript never makes updates of the first kind. We only make compat-breaking changes where we believe you should always be OK modulo a small number of fixes we think you'll be happy making (because we found new bugs).

We're not going to take a major version bump because there was a bug in the compiler where it failed to identify early errors, even though that's technically a breaking change - we think you should be "along for the ride" on that one if you didn't shrinkwrap. That's how semver is used in practice by everyone anyway.

@mhegazy mhegazy closed this Apr 19, 2017
@eddieajau
Copy link

@eddieajau eddieajau commented Jun 15, 2017

Can we at least get a section on "TypeScript and Semver" added to the docs? The fundamental problem is that npm install --save typescript will add `"typescript":"^2.4.0" by default. Consumers need to be aware that this is dangerous and you need to change it to "~2.4.0" (tilde, not carat). I'm happy to do the PR if you can advise on where you want such information.

But for what it's worth:

"You will probably need to update your code in a lot of places" ... TypeScript never makes updates of the first kind.

The Promise changes in 2.4 is resulting in lots of little changes all over the place. I'm not saying I don't agree with the changes, but they are there nonetheless. I've been caught only because I've [wrongly] assumed that TypeScript was following Semver.

@daprahamian
Copy link

@daprahamian daprahamian commented Jun 21, 2017

I'd like to add a related question: should type definition files be compatible across all of 2.x.x? Can someone compile their library in 2.2, and have it work when someone pulls it in and compiles with 2.1?

@DynConcepts
Copy link

@DynConcepts DynConcepts commented Jul 10, 2017

I too would prefer SemVer, and yes I know the majority of publishers are not "doing it right"...But lets look at an earlier comment:

"If we followed semver rules exactly, literally every single release would be a major version bump. Any time we produced the wrong type or emitted the wrong code or failed to issue a correct error, that's a breaking change, and we fix dozens of bugs like that in every release. "

Writing quality software is hard and requires investment. The above can be mitigated with improved testing and documentation.

Remember the Agile principle: "the art of maximizing the amount of work not done--is essential. ". This should not mean the amount of work done by a team to get something out the door. Rather it should be a global optimization to minimize the work required by all stakeholders globally and across type - the TOTAL work.

@daprahamian
Copy link

@daprahamian daprahamian commented Jul 11, 2017

If it is not possible to follow semver, could we come up with some sort of way to enable backwards compatibility / legacy behavior in our code? I am currently dealing with two major issues that I view as breaking changes:

Consuming a library where the .d.ts files are compiled in TS version higher than my project.

Example: Using TS 2.0, consuming a project that exports an interface with a member that is of type object.

A few ideas on how to fix this:

  • Allow TypeScript to compile to a previous version's output.
  • Allow TypeScript to compile to multiple versions of types output, and then include a root file that routes the consuming compiler to the right definition using some sort of markup (comments, conditional compilation, etc.)

Consuming a library where the .d.ts files are compiled in a TS version lower than my project.

Some examples include:

All of these issues stem from stricter type checking introduced in a later version of TS. This could probably be mitigated by doing the following:

  1. Having .d.ts files contian the compiler version via comments
  2. Having the compiler check the imported code's compiler version, and only apply new/stricter rules if they existed in the compiled version.

@jsamr
Copy link

@jsamr jsamr commented Nov 23, 2017

And what about a new package.json property : "breaking" which values can be "MAJOR" (default), "MINOR" ?
See npm/npm#19231

@FranklinYu
Copy link

@FranklinYu FranklinYu commented Jun 8, 2018

Fixing a performance bug, which would in theory be a bugfix version update, could cause two async operations which previously always resolved in one order to instead always resolve in another order.

If the resolution order is documented, then indeed it is breaking change and should bump major version; otherwise it is implementation details and user is responsible for depending on this.

@calidion
Copy link

@calidion calidion commented Feb 6, 2019

@mhegazy You have my full support. Semver is evil. And should be rejected everywhere. Typescript is a very good example.

@eps1lon
Copy link

@eps1lon eps1lon commented Feb 6, 2019

Fixing a performance bug, which would in theory be a bugfix version update, could cause two async operations which previously always resolved in one order to instead always resolve in another order.

This is one of the go to arguments against SemVer and it's a classic strawman. The very first point of the SemVer spec invalidates the argument here that "semvers own definition is wrong. here's why:"

  1. Software using Semantic Versioning MUST declare a public API. This API could be declared in the code itself or exist strictly in documentation. However it is done, it should be precise and comprehensive.

If your public API declared that two operations resolve in a given order then, yes, a performance fix is probably a breaking change. However I don't know any library that declares two public functions and declares that one is always fast than the other.

I agree if you don't have a public API then the SemVer is meaningless. However most of the issues with SemVer are a result of a problematic public API. Also https://xkcd.com/1172/: Just because a change breaks a workflow does not mean it is a SemVer breaking change if the public API never documented that workflow.

@justinfagnani
Copy link

@justinfagnani justinfagnani commented Mar 19, 2020

TypeScript not following semver has some serious negative implications in an ecosystem that builds a lot of features around the assumption that packages do follow semver.

Since npm installs libraries with a default version range that allows for newer minor versions, the command npm i typescript will install an unstable and occaisionally breaking version of TypeScript. Collaborators on a project may get different versions when they install, and may get different sets of compiler errors. Fixing them for one developer may break things for another. Yes, projects should override the npm default, but they have to understand TypeScript's unusual versioning scheme in order to know to do so.

Even worse, an upgrade to a new minor version of TypeScript may break users of a project. We don't have any indication through version numbers of which .d.ts files are compatible with which versions of TypeScript. A project that implicitly upgrades TypeScript to a breaking version due to breaks occurring at minor releases, builds, and publishes a new version with newer declaration files, will break consumers using an older version of TypeScript. Some users can't even choose their version due to the compiler being integrated into their build system / runtime (Angular, Storybook, TS-Node).

By adopting semver TypeScript would be a much better citizen in the npm ecosystem and reduce unintended breaks.

@calidion
Copy link

@calidion calidion commented Mar 19, 2020

It is semver's problem not typescript.

semver is the most misleading rule set ever.

npm's default rules make things worse.

as now npm Inc. is sold to Microsoft, maybe we can see further advance in npm.

@treshugart
Copy link

@treshugart treshugart commented Mar 20, 2020

How is semver misleading?

@calidion
Copy link

@calidion calidion commented Mar 20, 2020

Semver is like some idiots claim that all human are straight, never know of LGBT.

@calidion
Copy link

@calidion calidion commented Mar 20, 2020

Rules are correct when they reflect the reality and wrong when they betray the reality.

The process of software development is far more complicated than just promise your packages to be consistent or not.

Breaks happen inevitably what ever your maturity is.

There are even architectural mistakes constantly happening in big projects by big companies.

Let alone some small software development teams.

It is totally wrong software development rules based on assumption not on reality.

Software development process is more engineering than theoretical.

as npm and semver has been ruining nodejs's stability for years.

It is time to stop using semver and remove npm 's version range for stablity's sake.

@treshugart
Copy link

@treshugart treshugart commented Mar 20, 2020

Rules are correct when they reflect the reality and wrong when they betray the reality.

That... that's literally semver.

TS folks, you make an awesome tool and you can do what you want and all, but this all really feels like a subjective justification that betrays the consumer. So what if you're on version 100, at least it means something to tools.

@calidion
Copy link

@calidion calidion commented Mar 20, 2020

versions should focus mainly on their functionalities and should try to keep compatibilities.

major versions for architectural changes.
minor versions for feature changes within the same architecture.
patch versions for bug fixes (regardless of their compatibilities)

the reality is that npm's introduced dependency hell due to semver and npm's version range.

maybe semver is more innocent than npm's version range.

But they are both wrong, they are now chained to amplify the incorrectness.

And they constantly claim that package maintainers violate their rules.

It is one of the most funny things ever happened in software development :)

@anilanar
Copy link
Contributor

@anilanar anilanar commented Jul 10, 2020

@calidion

Some respected libraries use semver, they always obey the semver rules and it is very useful for consumers.

If you are going to rant, go to twitter.

@justinfagnani
Copy link

@justinfagnani justinfagnani commented Jul 10, 2020

Can the maintainers here please remove calidion's last comment? @DanielRosenwasser

@microsoft microsoft deleted a comment from calidion Jul 10, 2020
@microsoft microsoft deleted a comment from anilanar Jul 10, 2020
@microsoft microsoft deleted a comment from DynConcepts Jul 10, 2020
@microsoft microsoft locked as too heated and limited conversation to collaborators Jul 10, 2020
@RyanCavanaugh
Copy link
Member

@RyanCavanaugh RyanCavanaugh commented Jul 10, 2020

🤦‍♂️

@RyanCavanaugh
Copy link
Member

@RyanCavanaugh RyanCavanaugh commented Jul 10, 2020

I thought this was implicit, but now I have to say it explicitly: Comparisons to Hitler are neither necessary nor welcome here, and anyone unable to debate the merits of versioning schemes without relying on that as a rhetorical device should rethink whether their participation here is going to lead to a constructive conversation.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet