I Was Wrong About TypeScript
triplet.fi
triplet.fi
[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.
- 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.
https://github.com/ihsw/toxiproxy-node-client/blob/master/pa...
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.
Interesting, choosing TypeScript over Scala.js; what does TS offer vs. working directly in Scala across the board?
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.
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 could imagine, that most JavaScript developers prefer this over nominative systems.
Thanks for the links, future looks promising indeed.
Still, the hostility from the "against" side (which also included Yahoo and a pre-Chrome Google) was enough to derail the effort.
This two tools are amazing and it improves working with JavaScript to the point of never wanting to go back to not typed JavaScript
Your existing minification step will remove the comments. But even if you don't remove the comments the code will still run.
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.
JS Jabber episode was great! Full of great insights.
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.
And throw the bind into your .emacs
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.
(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).
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.
At the time it was compared to jQuery spaghetti code and Backbone with a little less jQuery spaghetti code.
It brought front-end web frameworks to the masses.
Granted I think they should've started Angular 2.0 a year earlier, but it was great at the time. Sadly is has aged very poorly.
In the last 4 months I've built a large angular1.5 app in ES5 using the new component facade and d3.js, and it's been pretty smooth.
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".
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.
I tried React but I hit a wall of needing synchronisation, routing, notifications, can you do that now?
The way I dealt (until proper type definitions are written) was:
declare module "react-loader" { var noTypeInfoYet: any; export = noTypeInfoYet; }
We use ts-node to run our mocha tests without ever compiling: https://github.com/TypeStrong/ts-node
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.
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"
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++.
You should aim for deployment process where outDir would be in .gitignore and building of the JS files would happen on a build server.
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.
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?
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.
Is there something I'm missing?
Let me know how that ends up working out!
[1]: https://github.com/TypeStrong/ts-loader [2]: https://github.com/s-panferov/awesome-typescript-loader
A.ts importing B.ts would be `import * as A from "./B"`, where the transpiled A.js file would import from `./B.js` rather than the original A.ts file.
Furthermore you can mix JS into your compilation process and the TS compiler will* accommodate you by compiling your JS alongside your TS code.[1]
* TypeScript 1.8
>[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.
When using the angular-cli,
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.
Further reading:
My only suggestion is start migrating to Angular 2 immediately.
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?
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.
Chances are that you'll love TypeScript though.
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.
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.
> 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'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.
Here's two things I saw on Jeff Morrison's (Flow author) Twitter:
* http://djcordhose.github.io/flow-vs-typescript/2016_hhjs.htm...
* https://gist.github.com/jeffmo/ef9214ca3acfe76c54a237b5710d3...
"Flow written in OCaml, Typescript in Typescript"
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.
Understatement of the century.
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'm actually no a sports person....
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.
Also VSC often is flunky with picking up defs... sometimes you open a file and some are missing.
Or imports with numbers don't work.
On the other hand, using big libs like babylonjs is charming with all the auto complete :)
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.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?
- 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...])
The self-documenting part is the strongest argument I've heard, but writing real documentation and real tests still seems better.
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.
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.
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.
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.
A: C's type system is very useful for data validation.
Please read at least one sentence before writing a response next time.
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).
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.
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.
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.
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.
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.
Thankfully this rarely happens.
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:
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.
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.
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.
Talking specifically Angular 1 if you have one, otherwise a general tutorial is fine.
I'm interested in whether it is worth the effort migrating a pretty large frontend codebase.
- Set up your TypeScript config
- Set up Typings (or some other type def manager)
- Rename all ".js" files to ".ts"
- 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.
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.
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.
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.
You're part of a MS project doing this, or you're doing it on your own?
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.
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?
It may still be a slam dunk to you, but it's not as "obvious" an answer as you make it sound.
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.
What tools are you talking about?
https://www.edx.org/course/introduction-typescript-microsoft...