With the arrival of TS 2.0 this month (hopefully) we'll have some cool features:
a union types [1]
b type guards to work with them [1]
c nonullable types [2]
As a Scala developer I like Typescript a lot. Which is a first for me in browser development.
But I'm not so fond of webpack et al. So I created a sbt-typescript plugin. And now I have incremental compilation of NG2 - Play apps for both the browser side and the server side. In a single build definition. It's a nice experience.
The two things coming in 2.0 that most excite me are
- moving types to npm (despite the great work of Blake on typings, managing type definitions is still out of band) - npm install @types/somelib will be great.
- AST transforms, which will open up some interesting options for bundling and optimizations, sort of like babel's plugin ecosystem.
If that first feature is true, it will bring me back to TypeScript. Honestly, my major deterrence of TypeScript was managing both 3rd party libraries and typing files.
I don't know about moving all of the current typings to beneath an NPM org, but TypeScript can look for the `typings` field in a package's package.json file.
An NPM package will be typed and you won't have to download typings separately. It may be improper to publish typings with your code instead of letting the user install them separately, but at that point it ceases being clean.
In this case, my `toxiproxy-node-client` package is written in TypeScript and the typings are published alongside the built package files. Compatibility between ES6 and TS is maintained.
yep, this method works great for libraries authored in typescript (and/or those that take the time to provide external module-style typedef files), but the @typings would be for what tsd/typings does today (mostly ambient)
I was just about to complain how TS fails totally for typechecking backbone models or immutablejs datastructures: both situations where obj.get("foo") and obj.get("bar") return a particular type but there's no way of having TS handle that except defining them as any. But it turns out string literal types in 1.8 will make that work. And this was out since February! I should reevaluate TS for my omniscient project.
The example you give has been supported since day 1. Example: document.createElement("canvas") returns HTMLCanvasElement. A limited form of string literal types has always been supported specifically for overloading return types. The newer support added in 1.8 is a way more powerful generalisation.
It could also benefit from constant propagation (iirc the term) where you could write obj.get(Item.name) and both get type check and stay refactoring friendly (though with cost of some more typing).
I am in the same boat as the poster. The main reasons I use typescript instead of scala.js are the vast amount of definition files already made (the scala.js translator of these leaves a lot to be desired), and the fact that it's closer to the es6 community which makes maintenance, contributions, and adoption much more likely. So basically because you stay closer to the JS world.
The only downside is lack of "isomorphic" code reuse which I gladly accept anyways because I rarely see server and client side code reuse as beneficial beyond simple models and validation.
I think the biggest advantage is that typescript emits code that is good JavaScript. This means if I decide to stop using typescript, I can just use the generated JavaScript. It also means that there transpiled file is smaller. Using scala.js for a small project wouldn't make sense if you cared about file size at all. It could be worth it more as your project grows, but your then you are that much more commited. There's no exit strategy like with typescript.
I'm always curious where that came from. TypeScript does not emit good JS. It's pretty garbage and not reasonably usable by humans. TS supports ES6 target, where it more or less just strips TS-specific features, but that's only useful if you target a very small subset of browsers and limit what you use.
Even "6to5" (previous name for Babel), which originally had as a design goal that it would emit good JS (and back then, it did!) quickly lost that when they tried to aim for spec correctness.
TypeScript actually punts on the standard in some cases (eg: TypeScript classes are not ES6 compliant) to generate more readable code, but it's still not "good" code and I certainly would never consider working with that.
I remember hearing the same argument in the early 80s for the benefit of C vs Assembly. And it actually was a good argument. A lot of people, myself included, learned "real programming" (ie assembly) by using C as training wheels. But a funny thing happened on the way to the forum - C became real programming and nobody remembered or learned assembly - myself included. Then the same thing happened ten years later with the transition from C to C++.
It did, and it will. My point is that just like with these "legacy" languages, the next generation of TypeScript developers are no more likely to "drop down into JavaScript" as a C developer is to "drop down into assembly". So our development tools and debuggers must be really solid at the language level that we code in. And just like I skipped the "transpiling" phase of C++, I'll probably skip the transpiling phase of TypeScript, and wait for the tooling and runtime to be more mature.
The advantage is it gives you an escape route if Typescript ends up dying. I worked on a project that had to do a giant dead language -> Java conversion, and it was extremely painful.
As codablah said: the availability of type definitions is a major difference in ease of use.
The other reason is that I can add a specialised frontend dev to the team and reasonably expect them to be able to work in Typescript.
I find it funny - the first language I learned was ActionScript 3 (built on ECMA 4 proposal) and I become a Flash developer aka laughing stock. I remember I had very rough time transitioning to JavaScript because it felt like a stone age compared to ActionScript 3. Then came TS and saved me and dare I say the whole web.
You should also have a look at Haxe, which comes from an ActionScript-inspired syntax, and compiles to JS (and a whole bunch of other languages, including ActionScript). It has even better language features than TypeScript (gotta love compile-time macros), although TypeScript has the benefit of adding features in an attempt to describe existing JavaScript code using types, so the interop with JS libs is easier.
Well, you still need some transpiling in order to remove the Flow type signatures. In practice, they end up being pretty similar in terms of needing a build step.
You're absolutely right. Flow seems to be a very good alternative.
One thing I would like to add regarding the .js files, TypeScript 1.8 added a flag --allowJs which makes some sanity checks to the plain old .js files.
It sounds like --allowJs alleviates the need to create TypeScript definitions for everything? So if you have an existing project based entirely on JavaScript, you can gradually convert each file to .ts without having to do anything else?
About the text editor: I think all editors use the same TypeScript compiler APIs. That would mean that you would get pretty much same suggestions, error lists, etc. Correct me if I am wrong. VS Code could have some other API calls or project file support.
JS Jabber episode was great! Full of great insights.
I use TypeScript from both Emacs and VSCode, depending on my mood. They do both use the same underlying compiler API, but the VSCode support is more pleasant in how it's surfaced in the editor: ctl-click on a variable to jump to its definition, f2 to rename the variable under the cursor, or ctl-T to open a query field to jump to a symbol.
Emacs is capable of all of these things (because Emacs is capable of anything) but it doesn't work that way out of the box nor is there an already-written package around that makes that easy. To rename you type M-x tide-rename-symbol and it's inconvenient enough that I forget to use it.
Coding/language support is very comparable between WebStorm and VS Code. WebStorm is a much larger and full-featured IDE, though. Most people won't use most features, but I found that I missed one or two things in VS Code and had to go back to WebStorm.
I'm still debating between the two. I do miss the code corrections (like the suggestions to add module imports) when using VS Code. That said, I'm very impressed with the progress that VS Code has made in such a short time.
WebStorm does offer syntax highlighting of HTML inline templates, but I'm sure that's a matter of time before that feature comes to VS Code. I do think that WS does provide a nice workflow at the expense of a much heavier tool.
Ashamedly at one point I was on the anti-Angular 2 bandwagon due to Typescript, because Microsoft. When I started learning Angular 2 myself I've found I actually enjoyed working with Typescript, for many reasons. (confidence that my code wasn't a ball of mystery before it ran, using inline templates, succinctness of annotations, etc)
At the same time, you're gonna need to use some preexisting libraries, and run into the issue of not having types available. (though they do exist for most mainstream libs) However, I found creating types for any given lib pretty flexible, and that you can usually get away with just enough types.
Ha, I'm on the anti-Angular2 bandwagon due to Angular1. I use React and Typescript and love it. Curious if you've tried React. Or Angular1
(TBH Angular1 was pretty great at the time, but after React I look back at those monstrous template files, ng-everything, plugins and workarounds, and only the bad memories surface).
Angular blew a loooooot of my trust in Google, who in the past always put out the highest quality stuff. I built an entire app in the damn thing only to realize as it got bigger that it wouldn't scale. Sure you can use less HTML templates, but that's the whole point so that it's easier for designers to approach / fix.
Sure I should have checked it out but the documentation didn't exactly highlight it (at the time anyway), and with the services, controllers, testability, etc it just looked like they'd thought it all through.
Frankly after finding React there's no way I'm giving NG2 even a look in.
That's a little harsh. It was an MVVM framework along the same lines as backbone, ember 1.0, knockout, and pretty much every other framework of the day, plus a lot of extra functionality. It's not really google's fault that MVVM has limitations.
Two of the main problems I had with angular - the template syntax and the way the digest cycle worked, both contributed to its scaling factor.
The template syntax meant you would always wonder what a parameter meant when passed to a directive. Essentially, all parameters passed to a directive were strings, but angular would parse some strings to mean "the property of a parent scope", and some more convoluted variations of that(check out https://docs.angularjs.org/api/ng/service/$compile#-scope-). Furthermore, using the recommended ng-controller directive created great spaghetti code, with template blobs where the current scope is almost impossible to track. Applying multiple directives to the same element sometimes required special parameter parsing, which further made the situation confusing. This confusion meant the more stuff you had, the more time you had to spend carefully memorizing it all so you knew what was going on.
The digest cycle fundamentally limits angular's scale. It was designed with some scale in mind at first - a digest cycle triggered at a specific scope would only run watchers under that scope, thus limiting the effect. I assume they hit the problem that there was no way to define explicitly "global" watchers, or to tell another scope to update itself. This issue apparently crept into the development of angular and local digests were pretty much abandoned in favor of using scope.$apply(), which triggers a digest cycle at the topmost scope. Local digests were not really talked about in the documentation, which was littered with examples of scope.$apply(), all of angular's provided directives used scope.$apply() and pretty much no one wrote any code limiting the amount of watchers triggered in an update. React specifically addressed this point with shouldComponentUpdate and the ecosystem built around it, which is one of its biggest performance benefits.
Further criticism would be the terminology confusion. Angular talked about directives, modules, controllers, filters, services, factories, providers, etc.
In essence, providers/factories/services were all just singletons instantiated in different ways(providers being the progenitor and factories/services being variations).
Filters were poorly named, as they were actually mapping functions or value formatters. Thus came the infamous "filter filter", which filtered elements in a collection, as opposed to say the "currency filter", which added currency markers to numbers. They were also incredibly inefficient, running on every digest cycle, even after the attempted fixes with "stateless filters"(http://www.bennadel.com/blog/2766-stateless-filters-don-t-ap...)
Controllers were essentially stunted directives, provided via the ng-controller directive. They were paraded as the way to start "simple" development, but led to a lot of bikeshedding about where to use controllers and where directives, the confusion around directives requiring controllers and the limitations around that, how to appropriately bind directive parameters to a controller's "scope"(not an actual scope but the controller function object itself), the bindToController function resolving that problem(introduced in 1.4?), etc, etc.
Modules were also a weird concept without much practical use. They do not provide a separate namespace(all your angular elements go into the same one), they don't leverage angular tooling to import your code(you have to import your code manually e.g. add script tags). Mostly they provided the config() and run() functions which would let you schedule code to be executed on-load.
I could go on and on about the confusion that angular's terminology caused, the microsyntax in its expressions and how interpolation worked, the scoping inheritance issues around directives and the subsequent overuse of isolate scope to avoid them, transclusion and how it affected scope inheritance(which led to articles like this one - http://angular-tips.com/blog/2014/03/transclusion-and-scopes...), the massive problems with there being no real directive lifecycle hooks you could use...it usually took a monumental effort to avoid all the traps and pitfalls of angular on any larger project.
That doesn't make angular necessarily a terrible framework, because it did enable some productivity when being fairly rigourous when using it. That rigour was developed by the community as it struggled to understand all the concepts thrown at you, but it certainly didn't come easy, and I'm not sure it became really widespread. This severely crippled "developer scale" for me, and the performance issues of watchers/filters worked against "performance scale".
Great answer, I feel the same way. Let's not forget the documentation, way too abstract. Probably the result of an overengineered framework.
Sadly I'm stuck having to deal with it, and I can honestly say I hate it and it makes me want to cry. Might have to do with the way it was used, though. I find myself having to write a directive each time I have to populate a fucking select2.
The real decision re: NG2 v React is more about opinionated frameworks v non-opinionated frameworks. If you're by yourself and/or have tight control over all of your libraries, React is fine. If you're a bigger operation and need to trust the restrictions of the framework, NG2 is possibly a better choice.
> I have written tests in TypeScript, compiled to JavaScript, and then used Mocha, for example, to run tests. I would like to hear your thoughts on this.
Another vote for ts-node running your tests, it makes things a lot simpler. Running tests directly instead of running compiled tests is faster and more reliable.
Mind being a bit more specific with "has some issues"? Our project isn't exactly small, and we haven't bumped into a problem yet. I'd really like to know what to expect if something is about to jump out from behind a wall.
As something of a side note on this post, suggesting there is a single 'Dart/CoffeeScript route' that languages can take seems a bit misleading.
Dart is a whole different language that happens to be transpilable to JS. CoffeeScript is just a dash of syntactic sugar that (IMHO) makes JS a whole lot less tedious to write ('The golden rule of CoffeeScript is: "It's just JavaScript"').
Notwithstanding that, I am keen to try using TypeScript on a new project one of these days.
Good point! I used similar categorising as Anders Hejlberg used in the JavaScript Jabber podcast (https://devchat.tv/js-jabber/209-jsj-typescript-with-anders-...). For those who don't like audio, he basically referred TypeScript being superset of JavaScript, unlike some other languages.
Often it feels like the CS professors I met at university, who wanted to teach you about "real programming languages and not such toys like JavaScript"
JS is very cool because of how readily available it is and the awesome ecosystem that has grown around it. That said - you don't have to be a CS professor to see that the language (especially in early incarnations) wasn't well designed, to put it nicely. A.H. knows this just like anyone with the skills to design languages and compilers.
Haha, I met him on a JS conf once. There was one of those old "JavaScript has no types and is no real language" guys and he kicked his ass.
Basically he said static typing could be good and there were languages like Scala out there with real good type systems, but most of the "pro static types"-fanboys are using crap like Java or C++.
Last week was my first week trying out Angular2 + TypeScript. I use mostly Java & C# at my day job. I was actually a really shocked at how fast i was able to gain a working knowledge of TypeScript. The only thing i don't like is my project has extra files everywhere (.js + .ts). However there is probably a way to make my IDE hide them or something.
If you use --outDir, wouldn't the .js files that import the transpiled .ts files need to point to outDir instead?
This is the kind of stuff that makes the "incremental" adoption argument hard for me to swallow. If I can't rewrite a .js file to .ts without any further ripple effects within the project, then it's not truly incremental.
I wrestled with this stuff last week and ultimately ended up going with flow since it gave me type checking _and_ incremental adoption, without complicating my existing babel/webpack stack.
Hey, I work on the TypeScript team. I hope you'll reconsider, and maybe you can fill me in on the issues you ran into.
Your .js files should typically be relative to each other, so unless you're using absolute paths (which you usually shouldn't!), this hasn't been a problem for other users. Is there something that I'm missing?
Hey Dan, thanks for responding. I think the key point you may be missing (or perhaps I missed a flag somewhere) is that I want relative requires but I don't want the intermediate js and sourcemap files cluttering up my project (and assuming I have an existing babel/webpack stack I'm happy with -- I just want the type checking).
I want the ability to convert any existing js file within the project to ts without having to touch a single other source file. I also want the type checker to assume that if I don't have a type definition for a package, that I don't want the use of that package to be type checked (without being forced to rewrite my ES6 imports to commonjs).
I was able to do this with flow but not typescript.
Hey rhymohr, I think I see what you mean. If you're already using something like Babel & Webpack, it should just be a matter of using a TypeScript loader like ts-loader[1] or awesome-typescript-loader[2]. TypeScript should just fit into that build step.
Hey Rob any idea why VSCode gives this warning on export class for Components?
>[ts] Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option to remove this warning.
WebStorm does a nice job of this. It'll compile on the fly for you, and it collapses the compiled files as child files under the .ts files. So by default you'll only see source files, but can expand and see output if you really need to.
It is fantastic - so glad you posted. On the transpilation thing; Babel still has a total use case. TypeScript doesn't provide es6 APIs such as Map / Promise / Array.find etc I output es6 from my TypeScript and pipe that into Babel to get the new APIs and to do transpilation. Works great. (There's a number of ways to do it; I use WebPack with ts-loader and babel-loader which rocks.)
Are there any patterns / recommended practices for unit testing Typescript. I recently joined a project which uses Angular1 + Typescript and had to introduce unit testing to the code base and it has been painful. A lot of backend API calls (wrapped in services) are being (chained and) invoked in the constructor. Any initialization is being squashed into the constructor. This makes setup of karma tests extremely painful/brittle without a complete refactor for each component.
However wrapping initialization code in public methods feel strange to me. Any suggestions?
I don't know exactly what your code looks like, but a major reason for using Dependency Injection, like AngularJS does, is to allow your tests to "mock" the injected services. Then, you verify the behaviour (but not the implementation), by checking that each mock is invoked with the expected arguments, and set it to return a particular value.
On the server side, I've used TypeMoq, which is pretty nice. I have only used it to mock imported modules; for AngularJS 1, you'd need to invoke the "inject" service, to insert your mocks into the controller.
I have found Angular 1 to be an untestable hot mess, especially on projects with a lot of technical debt. This is largely unrelated to TypeScript (and probably unrelated to Angular 1's shortcomings too).
My only suggestion is start migrating to Angular 2 immediately.
I just can't justify writing my team's code base in typescript. I don't want to make that move, setting us down a very specific path. I don't want to add another layer of training to develop on our codebase, but mainly, I just don't have the confidence that it's a right or wrong choice, and its a big choice.
But I get a sense that it would be great to try for smaller, disposable projects as that's limited risk.
Does anyone else struggle with TypeScript simply because of how big a choice it can be?
My impression of TypeScript, is that the .js it produces is actually extremely legible. This is especially true if you mainly use it for strict typing.
So in theory you could give it a go, and if you decide you don't like it after a while, you could continue development on your .js files and ditch the .ts files.
It also depends on how deep do you want to go with language features.
Let's say you have existing ES2015 source code. You could start experimenting on a local machine and use a script to rename js files to ts. Run the TypeScript compiler and annotate some of the most used functions.
You can then check what is the experience of using those functions that have type annotations, what is the speed of the development, etc.
Sit down with colleagues, show what you have done and ask what do they think. You can then decide to proceed and stick with type annotations until you're sure. Use boy scouts rule: "Always leave the campground cleaner than you found it." aka add typings to the function declaration.
The advantage of TypeScript is it emits idiomatic js. Decided that optional static typing is more trouble than it's worth? Fine. Bin your ts and keep the js. The code is totally fine. This is the attitude our team adopted when we first tried it out back in the 0.9 days. We didn't go back. You won't want to either
What "level of training" are you talking about? TypeScript is a JavaScript with opt-in types. Rename .js to .ts - it's a valid TypeScript file. You can gradually enrich the code base with type information, while still keeping old stuff intact.
One of the huge benefits is that you can start using "future" features (like sane variable scoping, for example) of JS now - TS will treat the code as "new", but downcompile it to what current browsers can understand.
You could start incrementally with Tx3's suggestion -
> One thing I would like to add regarding the .js files, TypeScript 1.8 added a flag --allowJs which makes some sanity checks to the plain old .js files.
Or burai's suggestion -
> Another good alternative is Facebook's flow. Rather than being a transpired language it works on top of JavaScript files.
I wrote in a previous post that I enjoy working with Typescript and overall it's a win for our team, but these days I sometimes wonder how much of a win over es6/7.
I've found the biggest headache is getting all the *.d.ts files setup right and setting up your own types can sometimes be a pain, but as I mentioned it's pretty opt-in.
You don't use TS because of the ES6 features. If that's your goal then you can simply stick with babel. You use TS because of the type checker, and that will not be part of ES6/7.
I found it easier to get started with Flow, but I eventually moved to TypeScript because it just has more mindshare, and isn't worse by any measure I care about.
I found it much easier to find tutorials, typings, and so on, for TypeScript. Editor support also seems to be a bit better (especially with VSCode), although the Flow-centered Nucleus plugin for Atom is pretty nice.
I'm not a huge fan of TypeScript (though I will admit that it's way more useful than CoffeeScript). My main issues with it are that: 1. The type definition files tend to get out of date. 2. The build step is time consuming for large apps. 3. It adds complexity to your app and opens it up to new kinds of errors (particularly during setup, different typescript versions...).
I prefer using plain JavaScript - When I need to find a definition for a function, I just do a text search for it in my IDE. Text search isn't as nice as intellisense for beginners but you get used to it pretty quickly and it's actually pretty efficient once you do.
I also like to read through the code a bit before using a function written by someone else, I find that just knowing the interface is often not enough - Often you want to know how specific edge cases are handled and it encourages you to fix bugs in other people's code instead of thinking "This class doesn't work, it's not my problem - I'll just hack a solution to work around it".
I signed up just to tell you that a slam dunk is not an easy shot. Its when the player jumps up and places "slams" the ball in the net rather then taking the shot from a distance. Its A) hard to get that close unobstructed and B) for most people hard to actually jump that high.
Its almost a boastful move of skill to slam dunk the ball.
This gives me the benefit of TS (specifically, typing), on my preferred development machine (Windows, where FB Flow is really crappy), while getting language-level polyfills (like generators) from Babel.
A nice side effect of having TS "compile" to ES6 modules is that Babel's nice-module-loading is used, which means I can just "import _ from 'lodash'" and never have to mess around with "* as" and the endless manipulation of .d.ts files.
That said, there are still things missing. In particular, object spread support, which is so nice when using Redux.
I've thought about maybe doing a Babel precompile, followed by TS for typing, then a Babel "real compile", but that's probably just crazy.
Not even Microsoft's own JavaScript libraries (e.g. Excel) have first-party type defs, at least as of a few months ago. Making matters worse, that aforementioned Excel library has polymorphic parameters everywhere. We gave it a shot with ng2 on a one-off, but honestly TypeScript just slowed us down and the juniors tried sneaking "Any spam" through code reviews.
No, I think solomatov is saying you can always use the 'any' type built-in to TypeScript. You can always do:
declare var fancyNewLib: any;
fancyNewLib('hello');
fancyNewLib.someCoolFeature = 3;
You don't get any suggestions or typechecking (obviously), but you're no worse off than just using JS in that sense. And you can easily replace your 'declare' with the actual // <reference> tag when you find it or make it, and clean up any errors.
Just changing the file extension from js to ts will often bring out bugs in your code. The type inference will often catch things. Functions that are declared multiple types or that have duplicate parameters, and a lot of other stuff will be caught.
Actually, it's better. If the core of your application has non trivial business logic, it's a good idea to write it in typed way and write ui and other support stuff with partially typed code.
Fair enough and I think with strict null type checking, where null/undefined isn't part of any anymore things would still get much better than with plain JS.
It seems like people are trying to use types as a substitute for tests and a way to protect themselves from unintended mutations.
But if you write tests already and use immutable data structures, what benefits does TS bring to people whose background isn't in strongly typed languages?
- Documentation. You don't need to have free-text comments saying "@param myArg must be a string", you can just look at the type signature, and immediately know how to use a function. Attempting to pass in a number will fail at the time of writing, not at runtime (of your test). This is a huge benefit when using third party libraries. For a JS lib, you need to read the documentation, and if something is undocumented you need access to the source code and the time to analyse it, to understand exactly how to use the lib. Compare this to making the type interface available.
- It's easier for a machine to read, which means the possibility for better tooling. e.g. linters and checkers, automatic refactoring.
- It's actually faster to write, due to the ease of making changes. If you move a function out to a new module, the compiler will immediately tell you all of the invocation sites that are now broken. (If you rely on tests, you have to make sure you have tests in every invoking module, rather than just the module you are actually changing. [Ignoring mocking issues...])
I'm not so sure about the "faster to write" since my IDE and linting will already take care of that. The java-style boilerplate is a huge turnoff for me, and the validation seems to produce false negatives so often as to actually introduce more bugs. Ie, If a variable gets mutated without changing type, TS is now worse than useless for validation.
The self-documenting part is the strongest argument I've heard, but writing real documentation and real tests still seems better.
An IDE can assist you even better when it can understand the code you're writing. For example, autocomplete "myString.re" without type hints, and an IDE like IntelliJ might suggest the method "reject()" (which is found on a Promise interface), or "remove()" (which is found on a DB entity interface), as well as "replace()" (which is found on a String interface). Wouldn't it be nice for it to always pick the right option?
TypeScript doesn't help with immutability at all. For that, you should look at something like PureScript. (Or GHCJS, or any other compile-to-JS languages that support immutability.) TypeScript assumes you are sticking with JavaScript's semantics, mutability and all. If you want immutability, you still need to use "Object.freeze()". Variable mutation is not something picked up by types alone.
There are other languages that introduce "dependent types", which can actually include values in their type signatures, which might be able to specify something like you want; i.e. "a function that accepts an argument of type 'a' which derives a number, and returns the same type 'a', but the returned value must be equal to the input value plus 10".
Documentation is nice... or so I've heard! Speaking for myself, developers are lazy and just want to write code. Why not make them document the code as they write it? Plus, external documentation (even as JavaDoc-style comments) always falls out of date with the code.
I think better than tests, is to enforce "design by contract" - assert your preconditions and postconditions on every function. This inlines your assumptions and behaviour verification with the actual code to be run. (If performance is a concern, you can implement this in a way that allows you to disable assertions.)
In general, the more guarantees you can enforce at compile time (such as only accepting certain types of values, or that input values are never mutated in place), the less need there is for having twice as much testing code as application code.
Refactoring. Say you want to make a 1:1 relation into a 1:* relation. You change your core data type from e.g. `type person{address:string}` to `type person{addresses:string[]}`, follow/fix all the red squiggly lines until it compiles, and generally you're done.
OTOH with unit tests, you've got to find/fix not only your app code but the test code as well. You may forget some things because you overlook a function and its tests. And of course your test coverage is likely not 100% so things may slip through.
So in addition to "refactoring", I'd add "guarantees": literally one line of code gives you 100% coverage.
PLUS autocomplete. JS editors have gotten better, but TS blows them out of the water. Importa new library, and stuff almost codes itself.
Mutability is somewhat orthogonal to the discussion. You can write things immutably or immutably in typed or untyped languages. I prefer mostly immutable too. But, going with it, I'd been a Clojure fan for a couple years, where immutability and dynamic types are both forefront. After rewriting an app in F#, and then performing a major refactor, this is what I had to say about it. https://disqus.com/home/discussion/owenrh/the_beauty_of_cloj... tldr: refactoring is much easier with types backing you up.
n.b. There's no reason you have to choose. You can have all three. Immutability, tests, and types. I do. Though if I had to choose, I'd pick types first. I'm a disciplined enough coder that immutability guarantees aren't that necessary, and if I've got types and discipline, then tests usually are unnecessary.
But doesn't Typescript compile to JS, thus there's actually no type-checking at runtime?
Certainly type checking can prove that it's the right type, but in my experience knowing that it's the right type but the wrong data is useless, I care if it's the exact data it's supposed to be.
How does type checking protect you (or someone else) from inadvertently mutating a value without changing it type and causing problems later? It's perfectly possible to do this without having any checks for class/instance throw a warning, unless there's something I'm missing.
> But doesn't Typescript compile to JS, thus there's actually no type-checking at runtime?
Sure, but that's what happens in every other language e.g. C's type system will enforce certain properties for you but when you compile to machine code the machine code is not checking those properties at runtime. If you know the compiler is correct you don't have to worry.
Nobody is saying you should stop writing tests but a good type system will mean you have to write less tests because the type system will do some of the checking for you in a more robust way.
You claimed that the lack of type checking at runtime is somehow detrimental to the notion. He pointed out that, fundamentally, all strongly typed languages run as weakly typed machine code at runtime, giving C as one obvious example. Thus, types in TS are at least as useful as types in C.
The concrete advantage of TS is the same as the concrete advantage of any strongly typed language - types let you do static validation, and unlike tests, they allow for that validation to be provably complete (of course, the domain of constraints that can be so validated depends on the power of the type system in question).
Yes, but what about mutating objects/primitives in a way that causes all validations to pass but still be passing the wrong data?
It seems like using type checking as a reason to write fewer tests actually just creates nastier bugs in areas where your coverage is based on type validation.
What am I missing about checking type mutation !== mutation being a problem?
What is the advantage of strong types if your data structures are immutable? Is there any? I'm genuinely trying to understand if TS is just for cases where uncontrolled mutation is the norm and test coverage is poor.
Immutability is also something you can model in the type system (not currently in Typescript, but it is possible in other languages).
That said, immutability by itself won't save you from passing the wrong shape of immutable object into a function, just as validating the shape of the argument passed and the argument expected against each other won't help if there are other assumptions being made by the code (such as that the object cannot be mutated). As one of the parent comments pointed out, types are proofs. Not everything can be proved to a compiler, but (assuming a bug-free compiler) everything which can be proved to a compiler does not need any additional tests. Things which cannot be proved to a compiler will need tests, of course.
> Yes, but what about mutating objects/primitives in a way that causes all validations to pass but still be passing the wrong data?
> What is the advantage of strong types if your data structures are immutable? Is there any? I'm genuinely trying to understand if TS is just for cases where uncontrolled mutation is the norm and test coverage is poor.
Can you give an example? I'm not following what you mean. Why would strong types be less useful if your data structures are immutable? OCaml mostly uses immutable data structures for example but its strong type system is fundamental to why it can be used to write such robust code.
Typescript has a stronger type system than JavaScript so Typescript can therefore capture more program properties statically compared to JavaScript whether you're using mutable data structures or not.
> knowing that it's the right type but the wrong data is useless, I care if it's the exact data it's supposed to be
Entirely possible people are comparing apples to oranges here. My experience is all based on structured data; e.g. User, Address, Order, Product, etc, and the relations between them. Data is generally static throughout the duration of the call; e.g. CRUD app.
It sounds like your experience is more with raw numbers and collections, and higher rates of entropy. In that case, I can see how types wouldn't add much value, and tests would be far more essential.
The whole point of strongly statically typed languages is that the proofs are performed at compile time. Statically typed programs shouldn't change behaviour after type erasure.
Languages with strong enough type systems can statically guarantee that data is structured correctly at runtime. Stronger structural requirements require stronger type systems. Algebraic data types are sufficient for many common static structuring guarantees.
You are correct, there is no type-checking at runtime. Getting garbage data where you are expecting properly formed data will throw a nasty wrench in your application.
It's not just javascript with types. The language is written in a way that makes it much easier for machines to understand your code. I'm not talking about just tests and linting.
Check out some typescript tooling videos, this one was shown at an angular 2 conference but you don't need to know any angular to watch it:
I find it funny that a lot of reasons boil down to "it's easier for the machine" -- developer happiness (which most of you mentioned, too!) through autocompletion and less failures seem to be a better selling point :)
A major benefit is the ability to quickly understand code you didn't write because you have the ability to 'go to definition' or 'find all references' which works across multiple files. On top of that once you understand the code and need to modify it you can quickly refactor across multiple files instantly and with a high degree of confidence.
Types are not a substitute for tests, but they eliminate an entire class of bugs that are screened out at compile time. That way you can focus your tests on functionality and not silly mistakes.
Which ide are you using? WebStorm, for example, gets easily confused about common JS idioms, which makes its tipped hinting useless in many situations. This makes refactoring a pain since you can't perfectly trust its warnings.
All the TypeScript fervor kind of passes me by because I simply don't want to structure my work around classes and 'ideal TypeScript' that I've seen looks a lot like Java or another class-oriented language.
Typescript is still extremely useful even if you are writing more functional code. There is no "ideal Typescript", TS is still ES underneath and just about all the ES paradigms including high functional code are still available in TS and benefit from typing information. (The possible exception being that TS is not entirely great at some of the more complex prototype-oriented paradigms, but even that has gotten significantly better in TS >= 1.8 with support for things like intersection types.)
Been using typescript since its introduction. It really helped me improve my JavaScript code quality and most importantly it's really good at keeping large projects tidy and easy to comprehend.
It would be interesting to hear more about your experiences. I have been quite hesitant to use more advanced TypeScript features and stayed on a type system related annotations.
In the blog post, I have one example of the React use case with screen capture.
I find it very helpful to have properties defined, so when I use the component, I immediately know what are the props I can provide.
There are some 3rd party React components that won't have type definitions yet, but the popular ones are well covered. I have written most of the components I have used, so I haven't had many problems.
My team uses it at work and love it. Both of them were new to me when I started (was using angular in vanilla JS) and it's been a really nice experience, the type definitions definitely help with learning a new codebase. I'm thinking of introducing typescript to my personal projects at home, but so far I've been too lazy to do the initial setup work.
From a React newbies's perspective, the React community is much more in the es6 camp than Typescript. Many of the starter kits are in es6. It's not a huge deal.
I actually write most of my front-end code these days in Aurelia, which is written in es6, but they actually have type annotations which Babel knows how to deal with. So basically the tooling can auto-generate the *.d.ts files for you.
That said, Typescript natively supports React syntax through TSX files, which is nice.
Shameless plug: When we've started switching to TypeScript and was looking for a good starter, we've couldn't find any that we've liked so we've created & open sourced our own. Maybe it can help people who are considering using TypeScript with React: https://github.com/barbar/vortigern
- Replace all "var x = require()" calls to "import x = require()"
- Gradually refactor components (controllers, directives, services) to classes, or at least add type annotations to everything.
Because TypeScript is a superset of JavaScript, you can work on an untyped system and add gradual typing until the codebase starts looking nicer. Any new functionality can be implemented in TypeScript; any existing functionality can be slowly refactored when it is touched by changes.
I'd add tslint to that once the basic migration is done. It can get a lot of issues in the code that are either bad stylistic options, or things that can produce errors in the future.
I don't see any reason to use TypeScript over Babel. I'm a big supporter of Microsoft technologies, especially since I started out my career developing web applications in the late 90's with Classic ASP. Then adopting .NET in 2000 and working in that space solely until 2011 at which point I jumped shipped over to the isomorphic JavaScript world of Node.js and Angular.
Over the past few years I've really taken to Node.js and Angular and when the Angular team told the world it choose TypeScript as its main language of choice to build out the new version of Angular 2.0, I had to seriously consider adopting it as well for Angular development going forward. If it's good enough for the Google team to use for Angular 2.0 then it should be good enough for me to use as well. Then during my research into the technology I ran across Babel.
After spending decent amount of time reading up on blog posts defending, promoting or choosing one of the two technologies over the other and alert spending countless hours building applications with each of them in order to get a real good understanding on how each feels to work with. I came to the conclusion that Babel is the only library I need to use on all of my projects and for good reason.
Babel provides the development world a tool that allows them the ability to use tomorrow's features and tools today and within mostly ever browser that's in use in some form commercially or professionally. Having the ability to use features in future ECMAScript standards planned for down the road today, makes perfect sense for me to use today if there will not be any side effects to doing so.
These features help me write less code, cleaner code and more robust code, just by using a library that handles all of the heavy work behind the scenes when it's time to transpile all of my futuristic code into today's boring standard for browser consumption.
Yes TypeScript can provide the end user a large portion of the features and functionality I am referring to with the Babel library but Babel provides the end user a lot more than TypeScript can and it will always be able to provide that and more going into the future as well.
I've often thought about a CoffeeScript variant with optional typing that transpiled to TS. The types would be ascribed via a backslash, e.g. `(hello\string) -> hello + ' world'`. But considering the huge benefit of TS is the tooling such as intellisence, I doubt it's worth the effort to start a whole separate ecosystem.
I envisioned it somewhat the opposite way. Gradual types a-la TS tacked onto CoffeeScript. No actual TS integration per-se.
Though even better would be if the TS team could figure out a way to factor out the type inference logic so that it could be applied just as simply to CoffeeScript as to Javascript, and even allow definitelytyped defs and perhaps intellisense logic to be reused everywhere.
Roslyn does this somewhat for C# and VB, so it might not be too big of a jump.
Contracts.coffee was great but sadly didn't live long. It would be worth reviving if there is an easier way to maintain it alongside mainline (iced) coffeescript.
Coffeescript was such a pain though, if something you wanted to edit was written in coffeescript, you'd have to learn coffeescript to touch it.
If something is written in typescript it doesn't matter if you don't know it. Just write what you want to change in javascript. All javascript is typescript.
"Love" is a strong word. The syntax is nicer than JavaScript, and I prefer to use it when possible. Though granted JS is making strides and the difference isn't as great as it was 5 years ago.
You're part of a MS project doing this, or you're doing it on your own?
At the high risk of starting a huge flamewar, I think the benefits of static-typing have won in a way.
I've been using Typescript exclusively as my transpiled language for about a little over a year now. The benefits of intellisense/code-completion and refactoring because of static types can't be underestimated, especially in large apps.
That said, I actually like the opt-in nature of Typescript. There's some parts of code I don't feel like I need to define an interface for. It's just not worth it.
Typescript is turning out to be quite a powerful little language...maybe approaching the point of quite a bit of complexity, but all in-all it's pretty much been a win for my development efforts.
I prefer frameworks that focus on pure javascript because the ones that don't tend to allow you too use javascript but have sparse documentation on how to use it effectively, instead focusing on typescript. When I first tried Angular 2 their javascript "hello world" example wouldn't even work, it was some bug in their site. I already need to use all sorts of other tools and abstraction layers when building websites/apps, typescript feels like just another abstraction layer (which it is), that means another vim plugin for typescript (or a bloated IDE), another npm dev dependency, another layer to the build process, so I try to avoid it for these reasons.
3rd party libraries / frameworks written with non-JavaScript languages is worth another blog post and discussion. I agree completely with you that libraries / -most- frameworks should be written in plain old JS.
The reason is simple, contributing and reading the project source code should not start by learning a programming language. It is a different scenario when a team in a company has decided to learn and write their project with TypeScript/CoffeeScript/etc. language.
About tooling, I think writing modern JavaScript (ES2015, ES2016) is beneficial and therefore, you need a tool like Babel. When you go to that path, why not use TypeScript instead and get ES2015/ES2016 + type system + great compiler?
(this won't be quite true after TS 2.0, but..) TypeScript doesn't support everything ES6 or even everything Babel does, and some of the stuff it does support are not matching the standard, in subtle ways. Then you're missing out on the Babel plugin ecosystem. You can use TS and Babel together for SOME of that (but not all of it, syntax parser and all).
It may still be a slam dunk to you, but it's not as "obvious" an answer as you make it sound.
I don't really work in the Javascript ecosystem, so when learning Angular 2 recently, I found all the other tools to carry far more cognitive load than Typescript.
The great irony of this (and fwiw, I completely agree, and I work on the angular core team...) is that by embracing platform features in ng2 we've opened up a mess of other issues to learn.
A good example of this is modules. Angular 1 had its own module syntax (partly because modules weren't really a thing when it started). You could write scripts, concat them together and go.
In angular2 we embraced ES6 modules, which means a developer has to deal with loading and bundling etc.
One nice side effect here though is we can leverage more tooling from the rest of the JS community (eg, the great work of webpack) rather than having angular-specific solutions.
[1] https://www.typescriptlang.org/docs/handbook/advanced-types.... [2] https://github.com/Microsoft/TypeScript/pull/7140
As a Scala developer I like Typescript a lot. Which is a first for me in browser development.
But I'm not so fond of webpack et al. So I created a sbt-typescript plugin. And now I have incremental compilation of NG2 - Play apps for both the browser side and the server side. In a single build definition. It's a nice experience.