Typescript is a truly great project, I'm not sure many people understand the amount of work that has gone into this compiler.
They have the crazy constraint of being 100% compatible with Javascript, which is a bit broken by design and yet they managed to make it so much better to work with TS than with JS.
After trying Flow numerous times, I came to the conclusion it simply can't compete with the power of the team Microsoft put together. Even their alpha versions are stable enough to be used in production.
Some advices:
- Always enable --noImplicitAny and --strictNullChecks. Without these flags, the type system is barely better than using JS.
- Use a noAny tslint rule. disable it on a case by case basis, only in util code. Most of the time, any is not necessary, often you can use {} or Object instead.
- You can get away with just using undefined everywhere, null adds no value.
- Use union types. Make impossible data combinations impossible to write! Example:
> - Always enable --noImplicitAny and --strictNullChecks. Without these flags, the type system is barely better than using JS.
It may be a good idea to add those flags for new projects, but if you're converting existing projects, that's just not feasible.
Further, you can actually see huge benefits just from switching to the TypeScript compiler without any changes to your code.
At my last company, we started switching to TypeScript just by running our large JavaScript codebases through the TypeScript compiler and installing type definitions [1] for the popular libraries we were using. While we were doing so, we started finding a lot of bugs in existing code that TypeScript was detecting for us automatically by inferring types from how we interacted with known libraries.
> - Always enable --noImplicitAny and --strictNullChecks. Without these flags, the type system is barely better than using JS.
This is exactly what I did and it's the main reason I keep dropping TypeScript because I 'need to get shit done'!
It's good advice though, and I would definitely advise new TypeScript users (especially those unfamiliar with type systems) to at least try it. But if it results in giving up and going back to just js, it might be worth going with the 'barely better' approach and only enable those flags if you're more comfortable with TypeScript.
1. Add `| null` or `?` for things that could be null/undefined.
2. Start handling "is this thing null?" cases. In some occasions it could be annoying. E.g. when you are absolutely sure it's not null. E.g. in tests. TypeScript provides `!` operator for that:
interface Baz {
foo?: string;
}
let bar = (t: Baz) =>
// yes, I'm sure
t.foo!.length;
Explicit any is usually also easy enough of a hassle to deal with: when you get a compiler complaint add an `: any` or `as any` somewhere and whatever necessary parentheses to scope that right. Optional: treat `: any` and `as any` as TODO or HACK markers to return to in the fullness of time (refactoring/fixing).
Dealing with other people's modules has also gotten much easier in recent versions of Typescript. To define a module name as any-typed the boilerplate has shrunk to a bare minimum:
declare module 'name-of-the-module'
Even better, module names in recent Typescript versions accept wildcards:
Mostly because it caused a huge list of error messages that I found difficult to get rid of. Some of it libraries, IIRC, and some of it my own code. Perhaps for some this would encourage them to one-by-one squash these messages, but in my case it made me go for what was familiar and not written in angry and red letters. I found it easier to introduce TypeScript from an opt-in perspective.
Although I don't use TypeScript (I'm looking at Flow more and more recently instead) I have to acknowledge Microsoft's huge contribution to the JS scene (and not only) with TS and VSCode, truly exceptional products.
What's more interesting to me is that everyone who converts their code into Flow or TS immediately finds at least N bugs (albeit small).
It's also quite amusing that this article came out today where HN's top article for a few hours was a bashing against Electron (and Slack specifically).
I like and have used them both, but for me there's two points that are massively in favour of TypeScript. The first, is that TS is written in TS, rather than OCaml. The second, is that Microsoft has a long history of developing and more importantly supporting dev tools, and is working on TypeScript for TypeScript's sake. Facebook is (and they're open about this) mainly concerned with Facebook's use-cases, and this drives their OSS products such as React(-native) and Flow.
> The first, is that TS is written in TS, rather than OCaml
I think being written in OCaml would be a benefit, rather than a negative. One of the reasons I'm interested in ReasonML, which powers Facebook's Flow, is that is based off of Bloomberg's Bucklescript, which is based off of OCaml.
I never knew the power of types (specifically algebraic data types) and the convenience of using them until I discovered them in F# (and Elm).
It's not that I'm against OCaml, I've tried to learn it a few times but the toolchain was a PITA. The benefits of self-hosting is that the more you use TypeScript, the more qualified you become to contribute, to troubleshoot, and to if-necessary help shoulder the burden of maintenance should Facebook/Microsoft decide it's no-longer profitable.
I work on Reason, mentioned above. The goal of Reason is exactly to expose a polished layer over the OCaml toolchain: http://facebook.github.io/reason/
I really like the idea of Reason & the community is pretty nice from my experience. At the same time, installing it on Windows is a huge pain. Windows 10 was feasible. Windows 7 (because Enterprises can't ever upgrade) is really hard to install it in my experience. I understand this has more to do with OCaml on Windows (which is odd since F# is very similar to OCaml). By the way, I should also mention that F# has Fable which compiles F# to JavaScript. It would be great if the Reason & Fable communities worked together if you're not already.
I was under the impression Reason was a library that let you write build files in OCaml? I'm not sure how this helps your average JavaScript programmer make sense of the source to flowtype.
Edit: Never mind, you're referring to my complaint about the OCaml toolchain. Carry on :D
Advancements in Typescript's typing benefit itself.
Plus self-hosting in this case also means that Typescript runs everywhere JS runs, including use cases of compiling Typescript on the fly directly in a browser or very easily including Typescript compilation in NodeJS toolchains or anywhere else JS may run.
I'm also really hoping that the current crop of JS programmers learn event-driven / reactive style programming, and for that, RX is probably the best JS library out.
Man, there's so many tools and styles to learn and evaluate.
I'm still relatively new to React and React Native, and have enjoyed writing some apps with Redux. It took me a while to understand the need for redux-thunk, and now I'm about to get started with redux-saga [1].
I'm totally unfamiliar with RxJS, but some of the concepts sound familiar. Do I need to learn and use RxJS if I'm already using redux and redux-saga?
I found this SO answer [2], and this post [3], which compares redux-observable and redux-saga.
EDIT: OK wow, as soon as you get to the "double click" stream diagram (in link [4]), it all starts to make sense. This is pretty amazing.
EDIT 2: The example on http://reactivex.io/ is also good. I didn't realize it was available for so many languages: Java, .Net, JS, Swift. This sounds like something I need to learn.
EDIT 3: This is the best programming guide I have ever read ([4]). It starts with a real problem, then goes on to show how you would solve it in RxJS in a rudimentary and familiar way. Then it expands on and successively simplifies that solution, to show how you would solve it in the idiomatic way. It's really the perfect way to learn these concepts.
> A metastream for responses looks confusing, and doesn't seem to help us at all. We just want a simple stream of responses, where each emitted value is a JSON object, not a 'Promise' of a JSON object. Say hi to Mr. Flatmap: a version of map() that "flattens" a metastream, by emitting on the "trunk" stream everything that will be emitted on "branch" streams. Flatmap is not a "fix" and metastreams are not a bug, these are really the tools for dealing with asynchronous responses in Rx.
Hi. I keep a big list of links to high-quality tutorials and articles on React, Redux, and related topics, at https://github.com/markerikson/react-redux-links . Specifically intended to be a great starting point for anyone trying to learn the ecosystem, as well as a solid source of good info on more advanced topics.
In particular, I have a category of articles for "Redux Side Effects" [0], which includes discussion of thunks and sagas, as well as comparisons between various side effect approaches. One particularly good article is "What is the right way to do async operations in Redux?" [1]. I also wrote a blog post responding to various concerns about use of thunks and sagas [2].
It's not js/es6 (re-frame is a react-based redux-like framework for clojurescript) but the author does a good job at explaining how reactive programming go well with functionnal programming and immutability.
That's one of my favorite repos to point colleagues to who feel overwhelmed by modern front-end development. Doesn't get bogged down in tooling or implementation details and explains at a high level the problems all these libraries are trying to solve.
It's a good foundation to crudely explain the pieces. React-Redux connected components are responsible for domino 1, Redux reducers domino 2, effects libraries like sagas/thunks/observables domino 3, selectors/getters for domino 4, React and the VDOM abstracting most of the concerns domino 5 and 6 away from you.
Obviously not perfect, but feels like it helps with choice angst a bit.
I spent a lot of the earlier parts of my life hating MS, however later after working at a .NET shop and with the late developments at the company, my love for MS is becoming near-infinite. Reactive is definitely the way to go
It's strange but I went the other way. I started hating MS because of working in .NET. Basically, if something wasn't blessed by MS, it wasn't used.
There were open source MVC projects but since MS only blessed ASP.NET forms back then, you couldn't convince managers to use MVC. Same with IoC. Same with ORMs
I do like the new Microsoft. VS.Code is hands down the best all-around editor right now. TypeScript is awesome sauce.
> There were open source MVC projects but since MS only blessed ASP.NET forms back then, you couldn't convince managers to use MVC. Same with IoC. Same with ORMs
VSCode and Typescript are stellar. In the case of Typescript, possibly industry-changing long term.
However, the .NET stack still suffers greatly from what you mentioned. The Microsoft world is like the Oracle world, you either use their stuff for everything or never touch it.
I'm confident that .NET core will change this when it's mature enough, but that's still ~2 years away.
> In the case of Typescript, possibly industry-changing long term.
I feel that way about a related Microsoft product, F#. It's too bad that it doesn't get the same amount of love as Typescript. I think it's more powerful yet just as easy to use in almost every way - I never knew how powerful or expressive algebraic data types could be until I used F#.
Repeating myself a bit in this thread. If you love F#, try checking out Fable &/or Reason. Fable compiles F# to JavaScript and Reason is Facebook's attempt at OCaml to JavaScript. F# !== Ocaml but F# == Ocaml
I've gone, and continue to go, both ways simultaneously. They put a lot of effort into creating awesome experiences to bring developers on board. They also run a business that caters to clients who need "enterprisey" stuff backwards compatible with COBOL.NET or whatever and try to push that along with the good stuff. So it goes. I can't complain too much.
I started here, too. First production app was an early C# ASP.NET OSHA safety management and training platform for Mohawk carpets, built from the ground up back in 2007-08. Experienced all these headaches. Next major project was Python-based. Never went back to .NET.
For me, I like how it's designed to complement the language, not to replace it with a (very closely related) cousin.
The conversion from JS-with-flow-types to plain JS is just a matter of stripping out that type information, which I feel is conceptually simpler than TypeScript's approach.
To me it doesn't matter that typescript replaces js because TS is forwards and backwards compatible, something nobody else is really attempting.
typescript (unlike Babel) is designed to output JavaScript that's as close as possible to what a human would write. If you get tired of Typescript you just transpile your code down to js one last time and forget about it.
Look at the output of Babel vs Typescript and you'll see what I mean about human friendliness. IMO the best tools are the ones easy to get rid of and typescript definitely scratches that itch.
Babel actually started with the express goal of outputting human-readable Javascript. It obviously hasn't stayed that way. IMO, Typescript hasn't stayed that way either. Trying to shoot for a compilation target that is useable as source code is pretty foolish.
The nice thing about Flow is that the compilation step is nothing more than stripping out the typing syntax. It is ACTUALLY easy to get rid of. I will say that the tooling is way better in Typescript.
Thank you, you've just summed up the entire proprietary vs FOSS debate _and_ the bus factor in a way that anybody could understand! I am definitely going to be repeating this wisdom!
Alright, I'll give you enums. I don't actually use enums because they have been superseded by string union types, which are generally better. (And are just types)
Decorators, interfaces, namespaces, readonly, private and there is probably more corner cases. Typescript compile to JavaScript and it smell like lock-in. In flow you can simply strip type annotations, and you are back to pure JS.
Decorators are ES7 stage 1 and can be found in Babel. (They were actually demanded by the angular team.)
Interfaces are types. Namespaces are namespaced types. Readonly and private are type modifiers. You strip out all of those and you have a working JavaScript program.
Decorators, and class fields, are pre-stage-4 ES proposals. That means they are not part of JavaScript. Moreover, what ends up eventually landing, especially in the case of decorators, is unlikely to work quite the same as what TypeScript implements.
So "Typescript has no additional features over (ES6+) JavaScript that are not part of the type system." is just false.
(Babel has plugins for all kinds of things that aren't part of JavaScript. The team is working on expressing more clearly which plugins are for experimental features and which are settled.)
GP was concerned about MS nefariously introducing vendor lock-in by implementing a bunch of their own proprietary features. I've demonstrated pretty clearly that
1. It's not MS's implementation - it's an implementation of an ES proposal.
2. For the one example you could find, MS didn't even want to do it - it was requested by Google for Angular and done as essentially a compromise. If you browse the TS repository, you can find issue after issue of the TS team refusing to add features that aren't part of the ES standard.
I think this shows fairly definitively that this is not a case of MS trying to lock you in to their product.
I'm not making a case for or against TypeScript; I'm just concerned that people be aware what is and is not part of JavaScript.
You said that TypeScript had no additional features except types. That's all I'm responding to: I'm pointing out this isn't the case. Class fields are, currently, not part of JavaScript. Neither are decorators.
(We're working on it - but actually a concern which has come up is that we might end up with something which breaks TypeScript, because the proposals are still in the early stages and therefore subject to radical changes.)
You can use `flow check`, but the server has the benefit of giving almost instant responses even on large code bases by only revalidating a subset of the project.
But Flow is actually a superset of JS -- without the types your code is perfectly valid JS, which is what actually happens via a simple Babel transform. Typescript is both a transpiler and a language, it's much further from pure JS. The actual advantage of this is you can drop Flow in any Babel project. With Typescript you need additional tooling.
They are both supersets. If you remove the non-JS features you have valid JS. But of course without removing it you have invalid JS. That's why both require tools.
Sidenote that Flow does allow specifying types through comments but this is a bit of a second-class feature.
Sorry, let me try to be more clear -- because this is a very real distinction which does have practical implications.
You can run Flow on ES code without changing it. If you have type annotations it will use them to help find errors, and you can use a simple tool to strip them out. The key thing here is that the "stripped" code is EXACTLY your source minus the type annotations. Typescript does not operate like this -- you cannot make assumptions about what the code looks like post-tsc. This is very important if you have some other tools, like Babel plugins, which operate on your code. You're likely to run into trouble if you want to use syntax Typescript doesn't understand or if a tool is doing some sort of code analysis.
Typescript is a language but Flow is much closer to a linter.
Sorry, Flow is a different language. The fact that it reuses a JS extension doesn't matter. Adding type annotations means that the language is no longer ES.next. The only reason Babel and the surrounding tooling understands it is because they, too, have been extended by Facebook to support said type annotations.
Try another ES.next tool, and it wont work. There are no type annotations in any ES spec.
Its the exact same thing, only MS is a bit more straight-forward about it (that its a different language). They are also siloed a bit more, perhaps - they could send a PR over to Babylon to add basic TS parsing support. But then they'd have to maintain that in sync with the original compiler.
If MS did what FB does, everyone would blame them for "embrace, extend, extinguish", pushing their own typed JS dialect by taking advantage of their influence in the JavaScript community, and falsely presenting it as "more JS" than the competing typed dialect.
I'm assuming FB have the best intentions, and I think they did it this way because they want to work with the existing open source community and standards bodies (avoid being siloed). But thats the only difference I can think of.
Ah, and yes, you can write all your types in comments. Thats a fair point. But it seems like they picked the most unergonomic way of doing this. The original extension supported this syntax
/*: (x: string, y: number): boolean */
function foo(x, y) {
return x.length * y === 5;
}
But thats gone, and current flowtype only supports this:
function foo(x /*: string */, y /*: number */) /*: boolean */ {
return x.length * y === 5;
}
I never said flow wasn't a different language or that it conformed to any ES spec.
> Its the exact same thing, only MS is a bit more straight-forward about it
This is what people are not understanding. Flow lints your code, then removes the types, leaving you with valid ES6 that is EXACTLY your source code without the types. Typescript is fundamentally different -- it transpiles your code and you cannot make assumptions about what that code looks like. They are not the exact same thing by any metric.
Typescript lints your code, then removes the types, leaving you with valid ES2015 that is EXACTLY your source code without types when you target ES2015 and stick to writing ES2015.
Typescript's transpilations are primarily to downlevel "future" ES features to previous ES versions (just like Babel). In my experience you absolutely can make assumptions about what the code looks like, and I have never been surprised by Typescript's output.
Typescript and Flow are a lot the same. Typescript has a few more "Babel features" built in.
The code is functionally the same but not identical, which like I said earlier can be an issue if you're using other tools which analyze/modify your code. I prefer Typescript over Flow for other reasons but the amount of misinformation in this thread is astounding.
Additionally, TypeScript's stated design goal is to not deviate from current or future EcmaScript [1]
You want more control over exactly what gets transpiled i.e. "I don't want to use ES.next, only ES6". Thats a valid point, but really far from your original assessment that there is a fundamental difference between the languages.
Your class is not syntactically valid ES2015. Typescript is allowing a shorthand that ES2015 doesn't allow and rewrites it to proper ES2015. It's a tiny babel plugin. Maybe a stricter output target should provide a syntax warning here.
The source conversion here, based on the implications of the shorthand, shouldn't be a surprising output and looks like perfectly readable, idiomatic JS to me.
Can you turn of those transpilations though? Readable code isn't the problem, equivalence is. Flow will never rewrite anything, which is what I've been saying.
Many of the transpilations you can turn off. The targets system turns off/on many transpilations as a suite. There are flags for several others such as `--noEmitHelpers`, `--preserveConstEnums`, `--jsx Preserve`.
If you have a reason to disallow and/or preserve something that TS does not already support, I would think the Typescript team would be interested in hearing about it.
But the argument I'm making is it's disingenuous to say that Flow and Typescript are both equally "not Javascript". Flow is _strictly_ additive to whatever else your toolchain is. Typescript is a different language.
I never said that Flow and Typescript are "equally" not JavaScript. I think you are getting your arguments crossed here.
Though I will state that both are not JavaScript, even if they are "unequally" not JS (for whatever that distinction means to you, though I think it is a moot point). Flow when used purely as comments is JS, sure, but the type annotation syntax is not JS as defined by any ES standard (except maybe ES4) nor any JS accepted by browsers (definitely not ES4). "Strictly additive" isn't a distinction that matters to what constitutes a language, if we want to be pedantic.
Finally, I would suggest you refrain from the word "disingenuous". Yes, my opinions differ from your own, but you cannot speak to the candor of my opinions here. I am hoping you did not intend an ad hominem attack, but I don't think a lot of people realize how much "disingenuous" is an ad hominem attack.
You're describing a property of their compilers as evidence that one is a superset and one is not. That TS transforms your code doesn't make it not a superset. It would not be a superset if it didn't support some JS feature. If it didn't support extends or something.
I'm not saying Typescript isn't a superset of JavaScript, I'm saying Flow is more direct superset in a way that's important. I'm more trying to clarify people who are saying Flow and TS are both supersets and therefore directly comparable. Specifically, the root poster's contention was that they're both supersets and therefore both "not JS".
They're different. Flow is not a "superset" of JS in that it introduces new features, it only introduces new types of annotations. Remove all the annotations (literally delete them), and you have valid ES6.
Typescript has its own class system, public/private/protected, and its own compiler. This was a big negative while ES6 was still brand new and the TS compiler was catching up, but now it's pretty much a wash between the two.
A year ago, I would have said Flow, no question. Today, TS has really caught up and the tooling is better, no doubt. It depends on how complex your types are - Flow can express types TS can't, but TS has an incredible ecosystem and far fewer bugs. In the end, it's all about reducing bugs in your own application, and TS seems to do that better in the end despite its limitations.
The class system was already an EcmaScript proposal at the time Typescript adopted it, and what Typescript launched with was directly based on the ES proposal at the time. The proposal shifted a bit before it was finalized and TS did the necessary catch-up work to the final accepted specification. It hasn't added anything whole cloth other than types that wasn't in some stage or another an ES proposal. (From that perspective TS has always been Flow + a few curated Babel plugins.)
Not true. Typescript does all kinds of transforms. Flow does nothing except catch type errors, and then it is simply stripped out. Nothing else in the code is touched at all.
I like that Flow is basically comments, rather than a new language. You can add comments to an existing code base and discover lots of bugs.
I don't think there are too many negatives with that system, although I will say having the type system deeply integrated with the debugger in TS is great.
I'll also say that while TS tooling is better, it can (sometimes) be really complicated to set up and understand.
I feel the same way. I'm eager to use Flow, but their tooling is just so far behind. Until it catches up I'm using TypeScript, which is much, much better than nothing :)
> What's more interesting to me is that everyone who converts their code into Flow or TS immediately finds at least N bugs (albeit small).
When I was playing with TS I converted a project and found no additional bugs. Type related bugs shouldn't be that common IMO (if they are and they're systemic (not like a one off) I would argue that there is an issue with the way you're architecting).
Maybe TypeScript just isn't for me. I see its value but didn't find it high enough to continue using. I'm working on creating a .d.ts file for one of my open source libraries but I don't know that I'll use it beyond that anytime soon.
To me, the value is at design/write time, not in converting old code. Old code that already works correctly will not be made more correct with TS unless you have branches of code that haven't been tested (by you during development, in tests or by your users). Working TS just lets me catch type mismatches while I'm writing instead of after the whole build process has run and I've reloaded the browser.
No, a test will tell you whether or not that test passes; it says nothing about the correctness of anything else. But at this point, you're doing the job of a typesystem.
> No, a test will tell you whether or not that test passes; it says nothing about the correctness of anything else.
That is a tautology: Of course a failing test shows you that the test failed. However, your test suite is severely flawed if the type system makes it redundant.
There's a whole class of type mismatch bugs, which can show up in one or more code paths of just about any practical program, and which can be eliminated by a type checker (instantly in your text editor if you set it up, or at compile time). If you are writing and maintaining tests for lots of these bugs, you should consider adding a type checker to do it for you. The difference in overhead between annotating a variable and writing a test is huge.
Which, again, proves my point: If your test suite can be reduced to a type checker you are doing it wrong. That being said, it does not mean that a type checker won't catch many of the same bugs tests do - but no more than a subset.
Yes, good tests is the only way to eliminate most bugs. But aside from overhead to add tools to a project (don't underestimate the potential difficulty of this), a type checker can cover its subset for free, and then you can get better test coverage overall.
Yeah, I think the bug-finding value is overblown. I advocate Typescript entirely for developer experience. It lets me codify complex domain objects and will catch the obviously wrong bugs while I'm developing -- things like passing arguments in the wrong order or passing an x to a function instead of a y. Not to mention with Webstorm or VSCode you have actually reliable autocomplete too.
> What's more interesting to me is that everyone who converts their code into Flow or TS immediately finds at least N bugs (albeit small).
Just rereading all your code carefully (which porting generally requires) generally finds a few bugs in my opinion. It might not always be because of typescript.
It doesn't port anything. Valid JS is valid TS, its just that the TS compiler processes it and tends to surface issues that just running it under Nodejs doesn't
Typescript's single biggest win for me is the ability to provide type definitions for my models. This is where the vast majority of my JS bugs come from -- somebody trying to access a nonexistent property of some object (or, if it does exist, incorrectly assuming the type) which was serialized from JSON. Better yet, if you write your back-end in Node you can use the same models in your rest endpoint. It's a huge boost to both maintainability and developer productivity.
However, my biggest frustration with Typescript is the general unreliability of @types. The odds that a given set of typings are complete, correct, and up-to-date are basically nil -- even for some relatively popular projects. Sad to say I've become an expert in Typescript's crazy module augmentation nonsense. Hopefully more big players like Slack contributing to DT will help.
In my ideal world, every library would be written in TypeScript and therefore benefit from their automatic type definition output, shipped as an invisible part of their npm package.
How does one validate typescript models at runtime? I have seen combinations of JSON schema and validator libraries but I'd love to do it using typescript's type system. From my understanding, it doesn't work because of type erasure.
AFAIK there's no good solution. That's why it works best when your back end is using Typescript as well -- your route returns the same interface the client is expecting.
Where can I find a good list of pros and cons for Flow and TypeScript?
I've been really enjoying Flow, and I have experienced all of the benefits mentioned in this article. I'm using VSCode, and the Flow integration is really good. Feels like a full IDE for Javascript, without being bloated and slow. (Startup is a little slower than Sublime, but it's very fast once everything has loaded.)
I'm wondering if I'm missing out on anything by choosing Flow instead of Typescript.
I've been developing React and React Native apps, and it seems like Flow is the default choice for that ecosystem. Has anyone switched from Flow to Typescript, and how did it go?
We like the fact that TypeScript is a full ES.next to ES.x compiler. No need to also include Babel and a bunch of plugins in the build.
But the biggest TS advantage has to be the size of the ecosystem. There are quite a few libraries written in TypeScript, and there are type definitions for pretty much all popular JS libs (and quite a lot of obscure ones). The Flow defs ecosystem seems to be fairly anaemic by comparison.
I haven't tried Flow. But there were a couple of practical things that influenced my decision when choosing between Flow and TypeScript:
* TypeScript has larger community.
* Flow requires Babel. TypeScript doesn't. One less dependency to worry about. And in my experience TypeScript compiler produces better JavaScript than Babel.
* Flow is written in OCaml. It could probably make it more difficult to install than TypeScript.
P.S. React works fine with TypeScript. I haven't played with React Native though.
That's a very good reason. I wish there were more community-provided types for flow. I think Immutable.js has only just fixed the last issues, but that's really been bugging me for the last few months. ("no default export" and "isEquals".)
* Flow requires Babel.
Not a huge deal for me, since React Native already requires Babel, and I personally like working with Babel. I use a number of Babel plugins, such as "transform-decorators-legacy" and "module-resolver".
* Flow is written in OCaml. It could probably make it more difficult to install than TypeScript.
Not at all, installation was very quick and easy. You can use either npm or Homebrew.
> I wish there were more community-provided types for flow.
One technical limitation that complicate contributions to the flow-typed repository is that there is no way of writing typings that depend on other libraries' types [1]. For instance, flow-typed has a library definition for `rxjs`, but it is not possible to e.g. add a definition for `redux-observable` that reuses the RxJS `Observable<T>` type, because there is no way to express that the typings of `redux-observable` neeed the ones of `rxjs` to function. So typings for such closely related libraries tend to not exist in flow-typed.
To work around this problem, some libraries like styled-components require you to manually include the library definition files it requires in your `.flowconfig` [2], but this is a rather hacky workaround.
Oh, that's a shame. I've spent the last few hours reading up on RxJS, and I just finished watching this talk on redux-observable [1], so I'm totally ready to dive in and rewrite some parts of my app. I was actually about to rewrite it with redux-saga, but I've decided that redux-observable and RxJS is far more awesome.
So are you saying that there are no flow types for redux-observable? I guess that's not a deal-breaker, since flow-typed will just generate stubs. Also, it looks like react-observable is a super high level abstraction, so I'm not even going to be writing that much code.
Could you elaborate on that please? Is it impossible to skip Babel when using React Native?
> Not at all. Installation is very fast and easy.
(Last time I checked Flow npm package gives you binaries.)
I'm sure Flow installs fine in "standard" environments, like an OSX laptop. I was thinking about more weird places, like CI servers where you can't fully control the environment. I was burned enough about stuff like that in the past.
It kind of depends. In some circles Flow is bigger. Mind that it is heavily entrenched in everything Facebook does, so it's treated as a built-in, first-class citizen in many circles (e.g. React Native).
> Flow requires Babel. TypeScript doesn't.
I'm not sure I agree. Objectively, depending on the kind of Flow you write, you don't really require any transpilation step.
Plus, subjectively, using Babel with TypeScript should not be frowned upon - there's a lot of advantages that Babel can provide that are outside of the scope of what TypeScript tries to do. Personally I use it to provide shims (via babel-preset-env) so I can target older browsers based on version configurations.
One thing I like about Flow for small projects is that you can use the Flow 'comment syntax' so that you can start using Flow and leaning on the typechecker without adding any transpilation setup at all. Flow's inference means many type annotations can safely be omitted, too. Example: https://github.com/jsdf/they-live/blob/master/handler.js#L11...
I find this especially useful for node projects, where there is less of a case for using Babel etc (node 7 supports all the JS features I want).
Having experience with both on Node back-end projects, I can tell you than IMHO Flow is smarter, especially on union types, BUT there are way more TS community type definitions available right now.
If you use discriminated union types - e.g. give them both a type key which is a unique string, then you don't need type guards as typescript is smart enough to understand that checking the type key does the type discrimination.
I've been using Flow+VSCode+React, and it's quite magical now!!!
With TS v2.2, I don't need to do any ugly hacks on TS to fit into pre-existing JS code.
Also, react support has been excellent since...TS 1.7 (or before?).
TSX checks for React PropTypes <div on_click={...}> or <div onClick={someBool}> so this gets rid of most of my silly mistakes :)
I've used TypeScript, Flow and Elm for making front-end apps. My favourite of the three is by far Elm, even if that was a bit harder to get into (as it's a new language and I didn't know before how to do side-effect free programming).
Flow is definitely a better type system than TS. TS types are "strong" in the same way as Java types. Flow is basically OCaml types, so a similar type system to OCaml, Haskell or Elm (except that you can give things `any` type). I am sure I will chose Flow over TS for that reason.
A ML-type type system (Flow, OCaml, Haskell, Elm, etc) is very powerful in that you can have abstract types, which means you can do basic composition of them. Things like the Maybe or Result monad for instance, which is very useful (and simple).
Typescript on the other hand let's you use the basic JS types, but it's not as extensible.
Do you have any examples to back up your claims? I don't think Flow's type system is more advanced than TypeScript's (which is not Java-like in any way).
What do you mean by "abstract types"? TS's type system is based around structural interfaces, so you're almost always working with non-concrete types.
It also supports discriminated unions, and you can emulate nominal typing with abstract tag properties.
PSA: That presentation is severely out of date and many of the negatives presented against Typescript don't apply anymore because of features added several releases ago.
Question for TypeScript users from someone who's still on the fence: Are you at all worried that TS will end up like CoffeeScript?
That is, it starts out with some great ideas that are quite easy to get behind, but JavaScript keeps on advancing year after year and soon you have the same features available but with an annoyingly different syntax, or you actually end up falling behind the curve. You're also not able to simply use the latest JS features, my last attempt at adopting TS died when I found it didn't at the time support object rest and spread properties, which I had been liberally using via Babel for quite some time.
It seems like Flow is a "safer" choice to me, but I'd love to hear if you disagree.
The delta between TypeScript and the JS standard is very small (for many TS users I expect it's a trivia challenge that they won't be able to answer: "write a TS program that isn't valid JS once you erase the types").
As you yourself point out, you were using features that weren't in a browser and needed a different transpiler to implement them. I think object spread still isn't even part of the standard(?) and you could imagine the standard diverging from the babel implementation of it, so the risk is mostly the same there.
The TypeScript team is pretty committed to tracking the standard, and e.g. turn down feature proposals that aren't far enough along in the standards process. See https://github.com/Microsoft/TypeScript/issues/16 for a feature users are begging for that they aren't implementing. Another good example is that they had their own module system which they deprecated in favor of the ES6 module system.
[disclaimer: big TS fan; I think Flow is fine too but I don't think it offers any advantage with respect to the issues you're concerned about here]
> As you yourself point out, you were using features that weren't in a browser and needed a different transpiler to implement them. I think object spread still isn't even part of the standard(?) and you could imagine the standard diverging from the babel implementation of it, so the risk is mostly the same there.
The TypeScript team's philosophy* is that they want to incorporate features that have either ~0% or ~100% chance of making it into ES. Types they put in the 0% bucket. Once a feature is near 100%, they'll include it. But if it's only at, say, 60%, it doesn't make the cut, for fear that it will change before standardization, leaving TypeScript in the "annoyingly different" situation you describe.
* - [edit: found the source] "We'd really like to hit features that have either a ~0% chance of making it into ES7+ (e.g. type annotations), or have a ~100% chance of making it in with easily-defined semantics (e.g. where fat arrow was two years ago). New operators are likely to fall in the awkward middle." [https://github.com/Microsoft/TypeScript/issues/16]
The TypeScript team has a goal of keeping it a superset of JavaScript. This means that when JavaScript gets some new features, TypeScript also supports that. If TypeScript supported it before with some other syntax, the syntax gets changed. [1]
The hero feature of TypeScript, static typing, will never be available in pure JavaScript based on any current prophecies.
--
[1] One reason the object spread/rest situation took so long was because they didn't want to implement it and then have to change the syntax/meaning later. It's better to wait until new proposals have gotten a decent amount of progress, so that they're fairly stable. Do note that spread/rest still isn't in the JavaScript standard, it's a proposal.
Side related question- has this going outside of standards with such things as Typescript been harmful? I mean, standards move slowly, but your question raises an interesting point - why didn't we just extend actual Javascript to have typing supported? Have we given up on advancing the core language in such regards?
ES4 attempted to add type support. (It's the ES version time forgot, mostly known only for forks it spawned like Adobe's ActionScript.)
Typescript and Flow both resemble, to different degrees, the type support that ES4 attempted (pascal-style `: typename` annotations being common to all of them).
Presumably the reasons browsers were not interested in ES4 remain the case today.
If that changes, then Typescript/Flow are useful playgrounds to explore what the standard could be. Many ES proposals now require "prollyfills" exploring that feature in the space of existing browsers as proof-of-concept, to help explore possible complications. Typescript and Flow do good jobs of "prollyfilling" type support, and I would expect that if a new attempt to standardize types in ES were to occur, they would both be looked to for advice/guidance.
The current delta between Typescript and ES6 is very small so even if you have an "abandon ship" moment it's probably a days worth of work to get your code compiling with Babel. In fact Flow's types are similar enough that you can probably use the same type information (or just pass it through babel-transform-strip-types).
Can't speak for anyone else but I started out using TypeScrip a while ago. Eventually Javascript just sort of caught up in terms of what was possible with the obvious exception of Type Casting. However after a while the annoyance of certain parts of TypeScript no longer outweighed the benefits I was getting from it, so I've dropped it and instead just use ES6/7 Javascript with Babel and in the end I'm much happier with it.
I'd be more "worried" to see JS/TS gradually disappear in favor of other languages that compile to wasm. If that happens, it won't matter which JS flavor or superset you're using. There's massive inertia behind JS though, so that'll take a while.
I put "worried" in quotes because I'm actually looking forward to using other languages. TS is a fantastic addition, but there's only so much it can do on top of JS, despite the great improvements in ES2015+. For example, I wish TS had a decent enum system with associated values and pattern matching (like Swift for example), but that's unlikely to happen.
Typescript is GREAT. Strict null-checking eliminates the dreaded null-pointer exception. It enables type-safe mixins. It allows for mapped types. Literal types, especially string literal types, makes it so easy to work with pre-existing JS libraries.
The way I look at Typescript vs. Javascript is that with Typescript, it's like having always having a pair programming buddy (the compiler) who never makes mistakes.
The new null-checking is great, but is notably missing first-class support for dealing with null. If you're familiar with Options (e.g. Java 8, Scala, Haskell), I've written a library [1] to fill that void until TypeScript does so.
> Strict null-checking eliminates the dreaded null-pointer exception
When I was using typescript this still came up if you missed an array bounds check, you'd end up with an unexpected undefined. Pretty annoying and tough to debug.
Has this changed (I can't see how it could have, but... maybe?)
Sort of. Strict null checking now lets you distinguish between the types Foo[] and (Foo | undefined)[]. The first will type with the assumption that there are no out of bounds indices (which, as you say, could be wrong). The second will require you to always check the result of array dereferences to see if they're undefined before you reference the object.
var foos1 = [] as Foo[],
foos2 = [] as (Foo | undefined)[];
// ... later
var foo1 = foos1[i],
foo2 = foos2[i];
foo1.bar(); // types fine, TS assumes non-undefined
foo2.bar(); // TS type error, as you haven't checked undef
if (foo2) foo2.bar(); // types fine, undef excluded
E.g. if I missed a bounds check, and access past the end of a `Foo[]`, it would be typed as `Foo` (and not `Foo | undefined`), but really be `undefined.
Consider this code.
var foos: Foo[] = [new Foo()];
foos[1].bar();
foos[1] will be undefined (since it's past the end of the array) but will typecheck as a Foo.
Obviously it's bad if I forget a bounds check, but it's similarly bad if I forgot a null check.
Of course, I understand why this issue exists, but it is an issue.
Will error because getElementById can return null. And it's 100% valid and imo 100% worth checking for - but I can't say I've ever heard of anyone doing it before Typescript suggested it.
Thanks! I wasn't aware of that. That said, I don't actually want to ignore it - I think it's good that Typescript is showing people some potentially errors they never thought to look for.
This pattern really isn't hard and if it saves you from one "undefined is undefined" then it was worth it.
Could you (or someone else) help me out here? I'd rather like getting an error in this situation, but in my code, with strictNullChecks turned on, TypeScript seems to be fine with the above... What am I missing?
> To improve our situation, we decided to give static type checking a shot.
I wonder why it took you years to realize this. I'd never use a dynamically typed language for more than a few hundred lines of code, it becomes an unmaintainable mess afterwards.
So serious question: Why?
It's probably worth pointing out that Slack _also_ contains a ton of native code, written in C++ (with a bit of C++/CX and Objective-C). All of us on our small team have an extensive background in typed languages, including giant code bases (Windows, for example).
We just also happen to really like JavaScript, feeling that it and the ecosystem around us makes us more productive given our needs. TypeScript a few years ago was simply not good enough, and neither were the alternatives.
It's okay if you feel otherwise, but trust that there are quite a few developers out there who are comfortable with building and maintaining rather large JavaScript codebases, building pretty impressive applications with it. This post isn't yet another "JavaScript is terrible" rant, I quite like it.
I'm right there with you, but dynamically-typed languages still have their advocates (though it seems they're losing out more recently).
(I think this is because a lot of the advantages associated with dynamic typing were in fact portable back to statically typed languages. If you're comparing C++98 to Python, the dynamically typed language seems pretty nice. If you're comparing Javascript to Golang or TypeScript, not so much.)
I have to ask the obvious, Flow vs TypeScript. I'm sure as React users you took your time weighing the two; care to comment on what drove your final decision?
I'll be careful not to tell anyone not to use Flow - we're using many of Facebook's tools and we're grateful for their gifts to the community. If Flow works for people, that's great!
That said, back when we got started, we found that TypeScript is all around a better team player. For us, we found that it worked better with npm modules, different operating systems, vanilla JavaScript, and various coding tools (VIM, Visual Studio Code, Atom, etc).
(1) It is less intrusive. Flow's type system is built on annotations which are simply stripped away at runtime (as opposed to writing in another - albeit similar - language that gets transpiled to JS. Sure the transformations are always "file-local" as TS folks say but still it is another, totally unecessary level of abstraction and transpilation.
(2) Flow's type system is at least equally and quite possibly much more expressive and nuanced than TS.
(3) Flow annotations can be applied in a much more piece-meal way than TS.
(4) zero issues integrating with 3rd party libraries (because of 1) - and that includes the ability to type-check said 3rd party libraries (which is a breeze with flow-typed)
(5) To take advantage of TS you have to write JS code in the "JS with classes" style (a.k.a "JS for C# coders"). In contrast Flow allows you to take advantage of its type checking while coding: (a) in idiomatic JS (prototypes) (b) in JS with classes (c) any combination and mix of the two approaches. Flow feels a lot less opinioned as to your JS programming style.
(6) Flow it is not coming from microsoft (but hey, don't you know we've changed, please give us another chance and we won't fuck you over this time, please we love you so). TS team is trying very hard (perhaps too hard) to distance themselves from the negative brand value of microsoft
(7) Flow is not a blueprint for the Mother of all embrace-extend-extigunish strategies (see #6).
I have not used Flow, but there's a few misconceptions about TypeScript in the above comment.
- There's an implication that Flow is vastly different than TypeScript because its annotations are stripped away - that's how TypeScript works too.
- There's an implication that TypeScript has some sort of unusual syntax - Modern JavaScript (ES6+) and TypeScript code is identical (except for the addition of type annotations where desired).
- Flow may have a nuanced and expressive type system - I don't know - but TypeScript attempts to accurately model the type system of JavaScript.
- TypeScript can be used in a very loose mode where it type-checks plain .js files with no annotations at all, all the way up to a very strict mode where it must know the type of everything (which you can set to `any` on a per-variable basis if you don't care).
- TypeScript is JavaScript, so it has no issues integrating with any JavaScript library. If you want perfect strong typing of a given version of a given JS library, someone has to do that work and this is where some people do struggle. Microsoft has put forth a lot of effort to help here recently. Flow-type may be a great resource (I don't know), but I can scroll its list of supported libraries on its repo on GitHub. https://github.com/flowtype/flow-typed/tree/master/definitio... . The DefinitelyTyped repo breaks GitHub with the number of libraries it has definitions for: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/mast... (nearly 2000 entries are omitted).
- Item 5 is flatly false. For example, TypeScript is itself written in TypeScript and there is not a class in the entire code base - it is 100% idiomatic functional JS. By contrast, Flow is not self-hosted.
- Regarding item 6, TypeScript is the poster child for the new Microsoft. It has been open source (Apache 2.0) and cross platform from its original release in 2012. And regardless of what happens with TypeScript (I forsee it tracking ECMAScript standards for the next several years at a bare minimum), the emitted JS is basically identical to your TypeScript code (minus the annotations) so worst case scenario if Microsoft somehow magically deleted all copies of TypeScript in the world, you'd just keep going with the ES6+ code you have.
I'll go out on a limb though and posit that classes are now idiomatic JS when doing OO. Shops are not cutting modern JS with objects built up via direct prototype manipulation.
Dunno, but I hope not. We built a moderate-sized TS codebase with _no objects at all_. Just functions and data types. Roughly functional ... with the caveat that nothing was preventing us from mutating incoming params (though our intent was not to do so).
I'd like to hope many people are using TS in a functional style.
EDIT -- there was one object ... we had to create an exception class for some reason ... don't fully recall the details.
Agreed. ES6 class syntax is superior to constructor functions and prototype mutation, because it's declarative and statically analysable.
I think the only legitimate reason left not to use ES6 class syntax is (for perf sensitive code) performance, but that's a negligible and temporary problem as the JS engines will fix that over the next 6 months.
Thank you. I wanted to say almost exactly the same thing, but you worded it much better than I could have.
Point number one in particular bothered me since both languages are transpiled (in both cases that just means types stripped). However, I think MarcusBrutus was talking about Flow type comments which can be added to Javascript files to get type checking, but which will not need to be transpiled at all as all nonstandard stuff is in the comments.
Flow is not a transpiler, there is no concept of "emitting code", only of stripping away the annotations. In contrast, TypeScript is a transpiler. TypeScript being a transpiler means what gets executed at runtime is not what you wrote but some other sources emitted by the TypeScript transpiler. You say that presently (apparently due to the delta between ES6+ and TypeScript being currently very small) what is emitted is not materially (for some definition of "materially") different from the input sources. Even if that's true, this is simply a transient situation that may not hold next year (we're still in the "embrace" stage after all) and certainly didn't hold when I looked at TypeScript circa 2013.
Otherwise, can you please explain why bother implementing a transpiler if the emitted sources are identical to the input sources minus the annotations?
Even the names should give you a hint: "TypeScript" is a language name (the microsoft version of ECMAScript more specifically). "Flow" is not. That's why it's called "Flow" and not "FlowScript".
Realistically, you are going to do the same thing with TypeScript and Flow, except with different tools: with TypeScript, you'll use the transpiler, and with Flow, you'll use Babel. In technical terms they are different, sure, but in reality they're basically the same. Unless you use the comment style Flow types, you will have to run your code through some stage to remove the types.
> TypeScript being a transpiler means what gets executed at runtime is not what you wrote but some other sources emitted by the TypeScript transpiler.
This is also true with Flow, if you want to be technical. What you write with Flow is not valid JavaScript (with the sole exception of comment style types) but some other sources emitted by another program like Babel.
If you haven't looked at TypeScript in 3-4 years, then you can't really make an informed opinion on the subject, because in that timeframe React has gone through 12 versions, Flow did not publicly exist, and TypeScript has changed significantly. It might be worth looking at TypeScript again and seeing how it compares to Flow in 2017.
You can use Babel to only remove the types, and not touch the code in any other way. And that's an important distinction: the code is exactly the same, just without types. I've been unable to use a Babel plugin at least once because of the way Typescript transpiled the code.
> Flow is not a transpiler, there is no concept of "emitting code", only of stripping away the annotations. In contrast, TypeScript is a transpiler.
TypeScript is a transpiler to the extent you want it to be a transpiler. You can use it to remove annotations only with '--target ESNext' - then it works the same as Flow does in your use case and does not add anything.
In the same vein, most people use Flow with babel. Then it's "transpiling" in the same way TypeScript is "transpiling".
You're either severely misinformed or opting to make your argument by misleading. I wonder how much you have actually used TypeScript.
> It is less intrusive. Flow's type system is built on annotations which are simply stripped away at runtime
> as opposed to writing in another - albeit similar - language that gets transpiled to JS
How is a nicely typed bit of flow-code different from the equivalent TS? If you make actual use of the type system in either of Flow or TS you should end up with code that looks a lot like Java or C#, with generic types and functions etc.
It's nice that you can do it gradually in flow for an existing codebase, but it's still no difference once properly applied in full.
Have you tried ScalaJs? Typescript seems like a better alternative to plain Js, but still seems pretty lacking. For example, the standard libraries are so much nicer than what TS or Javascript offer.
My suspicion is that the ease of porting an existing JS codebase to Typescript is an order of magnitude easier than rewriting it in Scala, even if the eventual benefit is higher.
Hey Felix, was Dart ever in consideration? I use both TS & Dart (I'm on a TS project currently) but I find Dart so much cleaner but the JS code it generates is very hairy. Thoughts?
I personally haven't spent too much time looking at Dart, but I find it pretty suspicious that TypeScript is on Google's list of approved languages for projects, while Dart is interestingly missing. I'm sure there's upsides to Dart, but I would certainly need to spend more time with it to make a judgement call.
Dart is doing fine inside Google. It is used by extremely important projects, like, for example Adwords. These teams are very happy with it and have no intention of changing.
Even though I work with Typescript daily, Typescript feels like a stop-gap measure until ES6 /ES.Next take hold. Dart feels like the future - given Fuchsia + Flutter + Android apps in Chrome, etc. - if they can just work out some of the rough edges(e.g. isolates with Flutter) and make it more harmonious with JS/DOM - let's face it: We are stuck with the JS/HTML/CSS stack for the foreseeable future.
Sorry, I just chose the image because TypeScript's official hero image is a Seattle skyline. I hope I didn't disappoint - I love Seattle though, I can't wait to be back this year for //build.
No worries, was mostly joking! I have a good friend at the SF office and hope to one day work with her again. That can only happen if your team opens some offices up here in the Emerald City :)
I think the parent is referring to JIT Compilation as a type of "compilation" as opposed to being interpreted. Of course the original post is tackling the type-safe aspect of compiling vs performance.
A slightly forked discussion, but having been in IT for over 30 years, I sense a theme...
A long time ago, people argued over the merits of assembly versus C.
After that, people argued over Pascal over C.
Then BASIC caused all kinds of consternation. BASIC versus "structured programming" was a common argument. With BASIC, there was this sort of wildness to it that drove people crazy. (this should be sounding familiar)
Then Visual Basic added structure (procedural at first, OO in .NET).
Then JavaScript was added to browsers and everyone cried that it was too unstructured and "wild".
Then Google Maps was released and JavaScript suddenly became popular.
Then NodeJS solidified JS as a real solution.
Now TypeScript comes along to make JS more "structured" and we have the same old arguments. Structure over low level unconstrained programming.
The weird part (to me) is that each side garners the louder voice about every ten years.
I'm pretty sure some new-fangled unstructured platform will arrive in 2020 that everyone will jump on and say is better. It offers freedom and the ability to sculpt a vision that the structured platforms don't.
One significant difference with the past examples you cite is that Typescript is gradually typed, so it's a false dichotomy you're presenting. Personally I think this is one of Typescript's biggest achievements, since the Typescript programmer gets to decide how structured their system should be.
Maybe. But anecdotally I've heard from more than a few JS devs that they'd _never_ learn TypeScript because it adds structure they don't feel is necessary and that just following ES6 is good enough.
> Maybe. But anecdotally I've heard from more than a few JS devs that they'd _never_ learn TypeScript because it adds structure they don't feel is necessary and that just following ES6 is good enough.
My guess is those were not an engineers, but script kiddies / code monkeys.
You're right, and this seems to be a common observation from people who've been in the industry for a while. My take on it is that software as an industry is still really young, nobody has got it "right" yet, and we're still figuring things out.
Its like arguments over AC and DC, or steam vs electric. We're zig-zagging between structured and unstructured platforms because they're all in the early days, neither of them are satisfying us so we jump to the opposite extreme. I think those zig-zags are getting narrower though as we converge on something ideal.
People flocked to dynamic languages because typing felt restrictive and redundant, now people are flocking to typed languages because of the assurances they provide. Modern type systems are getting better at giving flexibility and avoiding redundant type declarations, while compilers are getting smarter about checking that the programmer wrote what they intended to write.
I don't believe it ever really happened like that. Yes, javascript gained in popularity but that's because you have to use it for the browser and the browser was and is a compelling platform. Google maps didn't run on javascript because it offered a "freedom and the ability" to create maps that other languages did not. In fact, recall Google created GWT over a decade ago. Companies have been struggling against the maintainability issues in JS and other languages the whole while.
C# and Java never went anywhere. Types never went anywhere; phpdoc, jsdoc, etc. Ruby best practices are becoming more "enterprise"; dynamic language abuses are being frowned on as communities have matured and projects have grown larger.
I'm sorry, but to me your interpretation seems overly romanticised; presenting some eternal struggle between two just-as-valid points of view. I just don't see it that way.
With TypeScript, it is more like opening up old wounds between structural and nominal subtyping. The error reporting one gets with structural subtyping are really chaotic. On the other hand, it really works when bolting a type system on top of Javascript.
- It adds complexity and unnecessary dependencies to the project and this makes it more brittle and more difficult to set up and get running (I often run into issues with it).
- Slows down your debug cycle (it typically takes at least 15 seconds to compile for a small project) so you can't test your assumptions quickly as you would with plain JS - You have to wait all the time and try not to get distracted.
- For an experienced JS developer like me, the vast majority of errors raised by the compiler are pedantic and not related to any real logical flaws - I spend a lot of time catering to the fussiness of the compiler instead of thinking purely about logic.
- Working with legacy JS libraries is a pain.
I will admit though that being able to look up references and usages of various classes and functions without having to leave the IDE is a nice feature - I don't really need it though because I got used to searching through my code with text-matching (sift) and by adhering to a proper source directory structure.
Surprisingly I have not run into those compile time issues. Maybe it's just my company's own infrastructure, but our TS projects, which can get rather large, all recompile in less than five seconds.
total side point, but did you know in visual studio code you can enable "editor.codelens" and it will show class references in javascript above the declaration - no typescript required.
Autocomplete is a big productivity boost too: VS Code will suggest methods on the object, then tell you exactly what arguments it takes and what types they all are.
Of course maybe you can have another system which reads in the code you have and autocompletes for you too.. after all, the type info is all there, it's just in a different place. Compared to everything in the function definition:
function foo(a: string, b: object, c: XMLHttpRequest): string
Coming from Javascript, Typescript and Flow have huge benefits which a much smaller learning curve than going straight to Elm. I recommend people who don't have experience with static types start with one of those two.
For reference to those choosing: I started using Elm 2 years ago, also coming straight from Javascript. Elm wasn't without its frustrations. My biggest learning curve with Elm was a couple things.
1) Reading the type signature. I didn't know how to search for "->". But once I figured it out, and paired it with what I learned about currying, it made a lot of sense.
2) Earlier versions of Elm had non-descript error messages. Nowadays, it's fantastic, better than most. It was a main focus of the language for an entire version.
3) Figuring out how you operate on values wrapped inside a Maybe without unwrapping it with a case statement. Once I figured out Maybe.map and how to chain them together using Maybe.andThen, it got a lot easier.
After I had more experience, my main slow downs were:
1) Still, figuring out how to chain Maybes together, when it's a bit more convoluted.
2) If you want to make a non-standard UI element, you still have to break out of Elm and do it in javascript, either natively or through ports. I was making a markdown editor at the time, and had to do this.
3) Decoding/encoding JSON from ports can be tricky with recursive data structures. It's easy when your data is easy. It is not if you don't control both ends, and can burn time getting it right.
I've only listed the stuff I had trouble with, but there are many many things right about Elm. The design decisions are...tasteful. I don't know how else to describe it, other than it feels like someone put a lot of thought into it, and made all the right decisions--like how people think of Apple products.
There are some rough edges, namely Ports, and a single giant reducer/update function. But the community is working on it. The one thing they did right is that you don't have to spend a day installing a lot of npm packages just to get an application up and running. So if you're thinking about trying Elm over Typescript, just jump into it.
one thing I wish typescript had was an ability mark typechecks as runtime.
Commonly I'll have a nodejs express app which serves an api and i've love a easy way to validate an interface against the payload passed in. Maybe it would be as simple as a function JSON.parseWithChecking<User>(payload) or some annotation to get the interface reflected and passed into this function at runtime. It's normally always at deserialisation that this problem occurs.
I do this with a custom jasmine matcher in integration tests, you provide the matcher with some objects (which all satisfy the type you are expecting) and the matcher tells you if the response satisfies the type. It's a bit rough around the edges, but has been very useful so far. I'd consider creating an npm module if there is interest.
Well, you could have one or the other and then just convert a schema to an Interface [1], or vice versa [2].
The reason I like schema-first is because a schema allows you to be way more strict about what's accepted in most cases, e.g. validating an entry via RegEx. It tends to make APIs safer and runtime errors more clear.
The article mentions multi-threaded desktop applications along with JS. Since JS is inherently single-threaded, what does that mean? Do they actually refer to multiple processes or some other magic?
Yeah, but Node child processes are actually separate OS processes, which behave quite differently from threads (higher overhead to spawn, separate memory). The same goes for web workers; they're more like daemon processes than different threads. So I guess this was just poor terminology in the article, not any new magic... :)
Last time I tried TypeScript we ended up abandoning it after having mismatches between dependencies and TS definitions.
We had to postpone upgrading libraries to wait for definition updates or write and maintain them ourselves. This was in the early stage of a project though, we needed to get a quick first version out in 2 weeks and it just wasn't worth the hassle.
Has this situation improved - I understand typings are no longer installed with a 3rd party tool/registry?
There is one significant change with TS 2.2, you don't have to use type definitions for libraries anymore. Since all JavaScript is valid TypeScript.
With out of the box setup the import from library that has no type definitions, works just fine. It returns `any` type, so you can use all libraries just like you would in JavaScript. So if you ram your head against bad type definition of a module, just delete it and continue using it like you would in normal JS.
I have become a create-react-app junkie but unfortunately TS is still not (officially) supported in it [1] so for the moment I stick to using flowtype.
I've been working in this kind of environment with strongly typed languages for a long time, but TypeScript might be the thing that gets me to go back & give JS another chance. Funny to be coming at it the other way!
I really don't understand why some developers are so happy with Typescript. Javascript was already years ago highly improved with transpilers like Coffeescript, Livescript etc..
IMHO this whole Babel, ES5, ES6, ES7, ES???, Typescript thing with it's countless options is much worse than simply Coffeescript with a dynamic type checker. I use the latter in quite some production environments currently. No need for Babel, Typescript, linters etc.. It really makes my life way, way easier, less npm modules, less bugs, less lines of code, much more readable, etc, etc..
And please, before you start preaching all those 'amazing' benefits of Babel, Typescript, linters, ES5, ES6, ESx, I come from that misery and it sucks!
Would you rather have your program fail at runtime instead of using a statically typed language? It really baffles me why so many people prefer dynamically typed languages and write large projects in them.
My apps don't fail at runtime because of type errors, at least, not that I remember. It really baffles me how many people need Typescript to avoid having type errors at runtime, what the hack are they doing wrong then? This is not C++, we only have a few types in JS, really hard to mess up for me.
It buys you a proper modern language that even the creator of Javascript praises. It prevents bugs because it's a better language than Javascript in many ways. Just write a few projects in it and you'll see for yourself.
Functions in Coffeescript:
->
=>
Functions in Javascript:
var myFunc = function(){};
function myFunc(){}
var myFunc = () => {};
in objects:
myFunc: function(){}
in classes:
myFunc(){}
Instead of wasting time on this, try to understand javascript, Why slack web app & desktop app(electron) is taking too much cpu & memory, it will help you...
I'm a strong opponent against type annotations in JavaScript. JavaScript only have a few types: strings, numbers, boolean, null, undefined, and Symbol (ES6). And annotating them feels stupid. Feel free to use Flow, Typescript et.al. but let the type inferencer do the work, not you. You should only have to think about the abstract meaning of the code. And pick good names for variables and functions.
In order to catch more parameter errors, your functions should throw errors if the parameters are incorrect!
They have the crazy constraint of being 100% compatible with Javascript, which is a bit broken by design and yet they managed to make it so much better to work with TS than with JS.
After trying Flow numerous times, I came to the conclusion it simply can't compete with the power of the team Microsoft put together. Even their alpha versions are stable enough to be used in production.
Some advices:
- Always enable --noImplicitAny and --strictNullChecks. Without these flags, the type system is barely better than using JS.
- Use a noAny tslint rule. disable it on a case by case basis, only in util code. Most of the time, any is not necessary, often you can use {} or Object instead.
- You can get away with just using undefined everywhere, null adds no value.
- Use union types. Make impossible data combinations impossible to write! Example:
export type RemoteData<D, E> = NotAsked | Loading | Refreshing<D> | Success<D> | Failure<E>