If TypeScript is so great, how come all notable ReactJS projects use Babel?


(Johnib) #1

I know the answer for such a question might be very opinionated. However, these opinions are the ones many of us are following, it is some kind of wisdom of crowds.

We have a large-scaled client-side project and we are about to switch to ReactJS. Having that, we would also like to switch from plain JavaScript, i.e. ES5, to TypeScript.

I have read and watched many ReactJS tutorials including few parts of some books. Basically, what I’m trying to say is; I have seen lots of ReactJS projects.

  • None of them was written in TypeScript.
  • Most of them was written in ES6 using Babel.
  • Some of them (mainly small projects), were written in plain ES5.

Why no one (or very few) combines Typescript with ReactJS?


(James Kyle) #2

Hi John,

I’m a member of both the Babel and Flow teams working at Facebook.

We see a mostly linear progression for the JavaScript community from the days of plain scripts, to adding module systems, to adding compilers, to adding type systems. Each of these are tools that people added on in layers as they were built and as the community learned about them.

When we were working on Babel, the biggest challenge was getting people comfortable with the idea of compiling their JavaScript code. Despite all the benefits of this, it wasn’t easy and it required addressing a lot of opposing concerns all at once. Focusing on the needs of the community meant that compiling soon became a sort of “best practice”.

Now we’re moving into this period of time when were pushing the community to embrace static type systems. We’re still in the early days, so it’s still a matter of teaching the community what this means and building out to the needs of the community. This is why you don’t see a lot of it today, but in the next few years I’m willing to bet it will be considered a new best practice for application development.


We built Flow because we didn’t see TypeScript going in the right direction for the community. For example, it purposefully does not attempt to be a sound type system:

Non-Goals: […] Apply a sound or “provably correct” type system. Instead, strike a balance between correctness and productivity.
TypeScript Design Goals

While there are plenty of people who agree that correctness and productivity are at odds with each other in this sense, since the beginning we have believed we can do better than that in a number of ways.

Note: If you’re unfamiliar, type “soundness” means that the type checker will always complain when your program is invalid. You can’t write an invalid program with a sound type system.

One of the ways we push for better productivity than TypeScript while remaining type safe is through inference:

function square(n) {
  return n * n;
}

square("foo"); // Flow Error: string is not a number

Notice how we didn’t write any type information for this to work. Flow is still able to figure out that this is an error through something called “flow analysis” (which is where flow gets its name).

Basically, using very little type information Flow can figure out places where things are incompatible even in an extremely large codebase. I’ve had type errors come up in Flow in files that have zero types written in them that are really complicated.

Here’s one I took a screenshot of for a blog post of mine:

In fact if you write a 10,000 line long file with no external dependencies with no types whatsoever. Flow should still be able to point you to where the errors are.

One of the biggest complaints about the productivity of type checkers is that when you’re just messing around with code the type checker can get in your way as it yells at you the entire time. When you’re trying to hack something together for the first time you don’t want to spend half your time (or more) fixing up every error just so your code compiles and you can try it out.

By having the Flow type checker separate from the Babel compiler you’re able to have the best of both worlds. You can keep editing code and just ignore the warnings as if it were a linter and then go back and fix them later.

The second benefit to that is being able swap Babel out with something that suits you better, whether that be something like Buble which does way less work than Babel or flow-remove-types which only removes flow type annotations if you don’t need to compile your code all the way down.

By having Flow work the way it does, we’re integrating with the community better and being more flexible for everyone.

Most people use just Babel today, in the future most people are going to use Flow too.

If you like TypeScript, that’s awesome. The more people using static type checkers the better and so I encourage you to use it. But I would also encourage you to try out Flow as well.

If you’re concerned about the experience of React with a type checker, I can tell you that I sit right by the React team and we will have a continued focus on making everything in the React community work perfectly with Flow. Right now I’m focused on writing documentation but in the near future I’m gonna spend weeks going over every little detail of all the popular tools in the community.

Sorry about the wall of text, I have trouble turning it off sometimes.


(Jasan) #3

A big factor in my company recently switching to TypeScript was Windows performance, even with the recent massive advancements for Flow on Windows it’s still painful to use and the tooling is miles behind.

If you work outside the San Francisco bubble and are stuck on Windows, Flow isn’t really an option at the moment.

TypeScript and ReactJS work great together but you won’t find many open source projects based around them - not really sure why, think people mainly build from the examples given.


(Remojansen) #4

Hi guys,

As a TypeScript user I see Flow as good news. It reinforces the idea of a static type system in JS as being something beneficial as James has said:

If you like TypeScript, that’s awesome. The more people using static type checkers the better and so I encourage you to use it.

I feel the same way about Flow. If you use Flow or TypeScript then you are doing what soon will be considered a good practice:

I’m willing to bet it will be considered a new best practice for application development.

I would like to comments some of James points in support of TypeScript.

function square(n) {
   return n * n;
}

square("foo"); // Flow Error: string is not a number

Notice how we didn’t write any type information for this to work.

I agree that for trivial cases like:

function square(n: number) {
  return n * n;
}

square("foo"); // Error

Adding type annotations like : number is not ideal. However, my personal experience is that adding type annotations in complex/large code bases can be extremely beneficial because it helps you and other developers to understand the code.

Imagine that you see the following on GitHub:

function register<T>(
    kernel: Kernel,
    identifier: ServiceIdentifier<T>,
    constructor: Newable<T>,
    dependencies: ServiceIdentifier<T>[]
): BindingInWhenOnSyntax<T> {
    // ...
}

It is quite easy to see what needs to be passed to this function and what it will return. You don’t need to call the function and see if you get or not get warnings. Also, if you are not on an IDE, this information is still useful.

I find that type annotations have a benefit beyond preventing runtime errors: the benefit of self-documented code. For this reason, I will bet that not only using a static type system will be considered a good practice in the future. I believe that using type annotations will also be considered a good practice in the future.

In fact, within the TypeScript community we already consider a good practice to avoid implicit types with things like the noimplicitany compilation flag. This is because optional type annotations and the type any “make typescript be not sound”.

You can keep editing code and just ignore the warnings as if it were a linter and then go back and fix them later.

This is almost the same in TypeScript. The TypeScript compiler will emit JS unless you have parse errors (i.e. syntax problems) so you can ignore the type errors and run your application.

The second benefit to that is being able swap Babel out with something that suits you better.

You can use TypeScript with your favourite build tool (browserify, webpack, …).

TypeScript is now popular thanks to the Angular 2 advertising but I’ve been a React + Redux + TypeScript user for over a year and all I can say is that they are a great combination.

The only library that I have found a bit of a pain with typescript is immutable.js. You can learn more about this issue at https://github.com/facebook/immutable-js/issues/341

I hope you will use Flow or TypeScript, static types will definitely make your life easier!


(GPLTaylor) #5

I agree with the use of Typed syntax within JavaScipt. I work on projects that change (a lot) and this means we are breaking the code every day. Now we have adopted TypeScipt we find the issues have vanished and the worst case is CI build failures. I can live with this as not every developer is a mad genius.

We use TypeScipt mainly for Interfaces. They are autogenerated from our MS API 2,1 service and means our models are kept in sync between or MS and JS family of developers. I work in an environment where the spec is thrown in the bin and re-written on the drop of a hat and before TypeScript I did a lot of crying :slight_smile:

I did, however, find it difficult dealing within Immutable and TypeScript so I made a little video for my team to watch… I put it here only to in hope it’s useful to someone. Please remove if it’s not suitable.


(James Kyle) #6

However, my personal experience is that adding type annotations in complex/large code bases can be extremely beneficial because it helps you and other developers to understand the code.

Yeah, I agree that when you are exposing an API for other code to use, documenting the API using types is useful (in fact using Flow types you can generate API documentation using documentation.js). But the point is that you don’t need type annotations everywhere in Flow to get something out of it. The places where you do add type annotations Flow ends up doing a lot more work for you because it’s able to infer so much (See this post).

If you aren’t telling TypeScript what to do all the time, it won’t do anything for you. With TypeScript 2.0, it is starting to do more of this, but it has a long way to go to match how much Flow is able to infer.

TL;DR: Flow does a ton of work for you even when you’re being lazy (or maybe you just don’t want to write type annotations everywhere, that’s fine too)


(Matija Grcic) #7

Use whatever works for you and the team. It’s pointless saying Flow does this TypeScript does that better. Both are good so use whatever clicks better with you. I was thrilled about Angular 2 at the beginning but then I’ve switched to React as I really saw no benefits of learning new syntax, looking at you banana in a box, for the sake of performance gains. When React was introduced along with jsx it was weird at first but then I’ve adopted it because, well, I liked working with it. I’m not saying Angular 2 is bad, far from it, great minds are working on it, it’s just not something I would use.

TL;DR
Use whatever works for you.


(Thomas Dalla) #8

"[TypeScript] purposefully does not attempt to be a sound type system"
Same as flow, no?


(Jeffijoe) #9

Flow being written in OCaml was a mistake if you ask me, why couldn’t they write it in JS so every platform had the same support? I tried running Flow for Windows and it made my PC unusable, and it’s a very beefy PC.


(Donald Pipowitch) #10

We use TypeScript with React and are quite happy with it. We looked deeply in either using Flow or TypeScript before. At the end we decided to use TypeScript. In our experience it was/is more mature, has better tooling support and is less coupled to a specific community (RxJS, Cycle, Angular, Ember…) while (in our experience) Flow is mostly used in the React community.


(Simkessy) #11

Microsoft just came out with a new Frameworks for SharePoint development is pretty much all the examples are TypeScript with React. I wouldn’t be surprised if you start seeing more examples over time.


(Euregan) #12

Maybe static typing is simply not that great.
Don’t take me wrong, it has very good sides, but in the end it’s a restriction. After all, Python is extremely popular, and yet not statically typed. There are many good points for using dynamically typed languages, and clarity can also be one of them, it really depends on personal preferences.
There is also a new trend lastly that moves from traditional OOP to functional, and well, functional is impossible to apply in a statically typed language.
BTW, that Flow example you provided looks more like duck typing than static.


(Abradley2) #13

Typescript is great. The React ecosystem doesn’t seem to work well with TypeScript without adjustments at every point.

Immutable.js
Requires workarounds to get it to work with Records. I want deep immutable structures (lists of records or lists of maps) but to still have types all the way through.

Redux:
You have to cast to get typesafety on stores. Boilerplate-y workarounds needed for TypeSafety on actions.

Also, if I want to switch to Preact, that’s oddly difficult. I was using TS 1.8 and it would throw errors in VSCode for having JSX in the file but "cannot find name “React”… TypeScript 's JSX support is tightly coupled to React. I think there may now be a workaround for this.

TypeScript’s performance (using 2.0 now) seems perfectly fine to me. If I can’t switch workspaces and f5 faster than the browserify rebuild can finish then I’m happy.


(Creep Gin) #14

I think James Kyle’s notion of “productivity” is quite different than the TS community’s. Like remojansen said above, in TS community, noimplicitany is considered good practice. The compiler can automatically catch some nasty bugs this way if you explicitly declare all types. The alternative, implicit typing, also saves time by eliminating some keystrokes. Which is more “productive” is up to debate.

I understand that this kind of thread will attract more Typescript defenders to post, but I still want to say that, after using both Flow and Typescript, our team choose Typescript in the end because of better tooling and IDE integration.


(Daniel Earwicker) #16

I’d be interested in a concise summary of where they differ re: soundness. I only know of one example (TS assumes bibariance for function parameters). This irked me when I first read about it, but actually I’ve been using TS heavily since 2013 and never actually hit a problem caused by this.


(Daniel Earwicker) #17

I’m working on a TS library to add very strong typing to Redux, you might be interested (I’d certainly be interested in feedback). https://github.com/danielearwicker/immuto

Re: immutable record, in TS 2 I’ve just taken to declaring an interface with readonly fields, and then using a simple helper fn called amend to update:

const p2 = amend(p1, { firstName: "Bart" });

Amend is just a thin wrapper around Object.assign({}, ...). This will become language-supported when object spread is added:

const p2 = { ...p1, firstName: "Bart" };


(Daniel Earwicker) #18

You should definitely look at Haskell. It’s probably the best known and most widely used purely function language in academia, and it’s statically typed.

Really these days the boundaries between static and dynamic languages are breaking down. Static typing is only restrictive to the extent that it stops you doing things that won’t work. Modern languages give you an “escape hatch” so you can change to dynamic whenever you find types too restrictive.

Also languages with type inference often have code that looks no different from dynamic. For example, in TypeScript, Flow and C# this line creates a variable that is statically typed as a string:

var s = "Hello World";

BTW Python 3.5 added some support for static typing.


(Joe Wood) #19

Worth pointing out that TypeScript 2.1 (likely) will support “partial” types, this makes it easier to support setState/Object.Assign and immutable.js. https://github.com/Microsoft/TypeScript/issues/4889


(Creep Gin) #20

I’ve been trying to push for that feature the first day I started using TS (6 to 8 months ago). Was there any indication that they will push for it in 2.1? I don’t think I’m seeing it in the 2.1 roadmap.


(Nico) #21

For those hitting up against issues with TypeScript and Redux, I highly recommend looking into RxJS. It’s very easy to implement a Redux-like interface using it, and it even solves some problems (like async reducers) that require plugins in Redux. And it’s written in TypeScript…