Hacker News new | comments | show | ask | jobs | submit login
Flow and TypeScript (engineering.tumblr.com)
146 points by msoad 9 months ago | hide | past | web | favorite | 97 comments

It's worth noting that with upcoming Babel 7 it is possible to strip Typescript types like with Flow and use it just as a typechecker/linter [1]. This means following things:

- You don't need ts-loader/at-loader with Webpack anymore. You'll lose typechecking during webpack build but you can run it as separate step. Your editor will show them as usual still.

- You can use all the Babel plugins with Typescript without running two compilers (should speed things up)

- Should add first class support for React Native as it uses Babel (or at least no more 2-step builds)

[1]: http://babeljs.io/blog/2017/09/12/planning-for-7.0#typescrip...

EDIT: For the curious here's my build configuration with Webpack demoing this with extra plugins https://gist.github.com/epeli/bb8ae386f9dbb2a4ae2159e1f265fd...

Some features like enums are not supported and why on the earth you want to lose the type checking?

You don't lose it. You use type checking like a linter, to highlight issues as you type.

If you also want to use it as an enforcer, you set it up as a pre-commit hook or a CI step or whatever you want.

The idea is not to be forced to typecheck on every little incremental build during development. Sometimes I _know_ what needs to be done to get typechecking to pass (I can see the type errors highlighted in my editor after all) but I don't want to have to fix it before running my code to see how it behaves, because maybe I'm just playing around with an idea.

There are pros and cons to typechecking and not typechecking, which is why both kinds of language exist. Annotation- stripping lets you get the best of both worlds.

Faster and simpler builds setups. And you don't really lose it as your editor will report the type errors. Flow is used like this all the time.

Tried this on a project of mine. Enums seem to work fine for me.

EDIT: There are some issues with enums indeed https://github.com/babel/babel/tree/master/packages/babel-pl...

Wouldn't the simpler build setup be to use TypeScript only for compilation? Why would you want to use Babel as well?

Babel makes it possible to do compilation that TS doesn't do. E.g., you can use esnext language features that TS doesn't support, like do expressions. You can also use babel plugins that add utility, like the Babel power-assert plugin.

>Why would you want to use Babel as well?

Because he thinks you can't do JS development without Babel.

From what I understand, TypeScript doesn't do any transpiling, so if you want to use ES6/2017 features, you're going to need Babel.

(I haven't used TypeScript yet, so I might be wrong)

Typescript has always transpiled to ES5 (by default it transpiles to ES3 actually). See: https://stackoverflow.com/questions/41173215/does-typescript...

The only counter-example that I know of is that async/await were initially only supported when transpiling to ES6, but this is not true since at least 2.2 (https://github.com/Microsoft/TypeScript/issues/5210).

It does transpiling. You can set the compiler target to es3/es5/es6 in your tsconfig.json and then you don't need Babel.

One of the common pattern I use when developing with TS is: Change a type definition, look for red squiggles in the current file and fix them then save and build.

The error log shows me the rest of the files that need fixing.

How would you get that with Babel?

I think this is just an editor concern. It could show a list of files with type errors.

But you could just run "tsc --noEmit --watch" which will just report the project wide type errors to the console as you edit files.

Yeah, it doesn't doesn't anything that is multi-file like const enums since Babel operates per file.

(I work on Babel)

This seems like a recipe for disaster after a bad merge. If you have a team of more than one, this sounds like a silly thing to do.

It's fairly common practice with Flow to run type-checks as a part of the build or test step in a standard build/test/deploy workflow in CI, which largely removes the possibility of bad merges arising from type errors. With TypeScript, using the TypeScript compiler, type-checking would simply happen in lockstep with your build step, whereas with the new Babel preset and a separate type-check process, you still have the option of running them in lockstep as 2 separate commands, but you also have the option of running them as separate jobs in parallel, likely leading to significantly shorter build times. It's definitely going to be a huge net improvement to my own workflow, but you're certainly free to stay with the status quo if you feel it suits you better.

Perhaps you could run the type-checker separately on a 'prepush' hook.

If you were going to do that, wouldn't it better to just use // @ts-check in JS files, a jsconfig.json for the Typescript compiler, and jsdoc pragmas?

For the same reason that Flow's dedicated type annotation syntax is the standard. It's just easier to use. This change will effectively make using ts as easy as using Flow, which is a huge win.

Interesting. From my perspective using Typescript and its transpilation power entirely instead of Babel is even easier still. There's a lot less complexity in my builds if I don't need to manage Babel. From that perspective, Typescript has always been easier than Flow, too, though some of that is also bias from how hard Flow has been to get working on Windows up until somewhat recently. I realize though that there are many perspectives on this issue and I asked the previous question because I was indeed curious about your perspective, thanks.

I'll update the post to give an idea of how it works, thanks!

We faced a similar situation in our project and went with Flow instead. We found a TS + Webpack setup too unreliable. There are couple of popular Webpack loaders (ts-loader and at-loader), and both kept crashing the Node process every other build. Build times were pretty high. We could not find any documentation on how to fix these problems, except for a few open GitHub issues.

We then tried Flow. Oh dear god, has it been a blessing.


* It's seamless to integrate with Webpack, ESLint & Babel.

* It's crazy fast

* Has great support for React

* Fits in perfectly with Redux

* Dead easy for beginners to learn

* Has an amazing Type system. My major experience with types has been Java, and Flowtype just blew my mind with - non-nullable types, subtyping and type refining.

* Documentation is great

* Community is very active


* About 1/3rd of the time error messages are not intuitive. But nothing you can not figure out. And it's getting better.

It's interesting to learn that the two sibling comments here (at the time of writing) both misunderstood the parent. Both in exactly the same way, too.

In the parent post, pcx shares his experience with trying to make TypeScript work, concludes that he wasn't able to make it work, then says he was able to make Flow work and lists ways in which Flow made his life easier.

Not even a word in the post suggests that the parent intended his "pros" list to be a comparison between TS and Flow. It's just a list of things Flow does for him. Not even one mention of TS on that list!

I don't quite understand why would one misinterpret a list of good things about one tool to be also, implicitly, a list of bad things about another tool. It's not politics, we don't need such polarization in technical discussions, saying that Flow has great docs is not the same as saying TS has bad docs.

But the real problem is that, by choosing to get offended by something entirely unrelated, the sibling commenters missed the one direct comparison between TS and Flow and a real TS criticism: parent says it's easier to setup Flow compared to TS. It would be better to discuss this point - I'm not qualified to do so myself, unfortunately - instead of focusing on statements the parent never wrote.

Let me add a few cons then

- Saying the error messages are "not intuitive" is a bit of an understatement. Most memorably, this was an actual message I was presented with after upgrading to Flow v0.53 - https://imgur.com/UseQxEz.png

- Flow's goal appears to be ensuring correctness rather than being useful. Object.value produces an array of mixed, effectively erasing their type (https://github.com/facebook/flow/issues/2174). document.body is a Maybe (https://github.com/facebook/flow/issues/4783). All use of getters and setters are marked as unsafe, with no way to selectively opt in or out (https://github.com/facebook/flow/issues/2826). These are pedantic to the point of uselessness.

- When a function call's parameter type disagrees with the function signature, Flow flips a coin and marks one of them as incorrect. GitHub issue from Oct 2016 - https://github.com/facebook/flow/issues/2587 (issue is closed because they're 'working on it', not because it's actually resolved)

- Flow's libdef is a fraction of TypeScript's. I frequently convert TypeScript libdefs to Flow libdefs. I have yet to see a library that has Flow libdef but not TypeScript libdefs.

What is your threshold for too long of a build time? I recently converted a typescript (angular 1.x) project from jspm to webpack. The front end build time went from 3 minutes to 30 seconds, but I don't know if that's still "too long" as I have no basis for comparison.

In my experience, a fast build is one that finishes before I can tab back to my browser. Compilers that can incrementally build my project are all I prefer to use.

I set up webpack-dev-server for that case. Saving a file refreshes the page in about 1 second (after 30 second initial build on dev-server start). Full build still takes 30, which is tolerable but I can't shake the feeling that there's another 2-4X speedup still to be made.

What about flow gives it better support for React than TS (other than it being built into the CLI)? Why does it fit more perfectly with Redux than TS? Why is it easier to learn than TS? Why does it have a more amazing type system than TS?

As I mentioned we couldn't get TS + Webpack to work properly. I am not dishing TS, I just couldn't evaluate it all that well. To expand more on your points:

- Flow has more & better type definitions for React than TS. I think it's because a lot more React devs use/develop Flow and also both are FB projects.

- For our Redux + Flow setup, we export an ActionCreator type that is a union of all action creators we've defined. This union gets refined by the switch statements in reducers, allowing us access to well typed action creators in reducers, without having to deal with import/export of individual types.

- The docs are pretty good. Several of my colleagues are new to static typing, and have picked Flow up easily because of the docs. I also heard some interest in providing video courses like Egghead.

- Flow has an amazing type system compared to Java. Except for enums though. Java Enums are much much better.

Flow bakes React libdefs right into the binary https://github.com/facebook/flow/blob/master/lib/react.js - so yes, Flow damn well have good React support, because the React libdef is given the same level of importance as Node and DOM APIs.

Of course it also means you can't upgrade React without upgrading Flow, and you can't target a specific (older) version of React without downgrading Flow.

> For our Redux + Flow setup, we export an ActionCreator type that is a union of all action creators we've defined. This union gets refined by the switch statements in reducers, allowing us access to well typed action creators in reducers, without having to deal with import/export of individual types.

What's stopping you from doing this in Typescipt?

I also take issue with some of OP's unsubstantiated claims, but I'd like to add my own piece of anecdotal experience:

The experience I've had around typing higher-order components in general, and specifically with the recompose library (https://github.com/acdlite/recompose), which I use heavily in just about every React project, has been much better in Flow than in TypeScript. Now this is not completely fair to TypeScript since the recompose types for it were still a work in progress last time I tried it, but recompose is a central building block in most of the codebases I work with on a day-to-day basis, so good typing around it is a vital consideration for me, and possibly others who prefer to work with React components using functional composition.

I downvoted since a majority of these things are valid for Typescript as well.

How is that a good enough reason to downvote? I haven't said they don't apply for TS. I am specifically speaking about my experience trying both TS and Flow.

Well yes, and you list a bunch of things as pros that are true for both tools but for one which makes it appear like Flow would have these features and not Typescript.

I think your pros read as pros against TypeScript, when many of them apply both tools.

I enjoyed seeing a side-by-side comparison of some differences between the two systems. It seems to mix tooling support with language features, but I think that's fair, because good tooling is essential. It would be nice to see some more examples, but clearly some effort went into this evaluation.

I'm surprised the author thinks that Flow is more popular amongst the React community than Typescript. I hardly ever hear about Flow, and I work with React and follow it's development. I've been gradually concluding that Typescript has won in terms of future-of-frontend, so I'd be curious to know if people disagree.

Yeah, the impression that I get is that TS has won as well. Initially it really offered a lot more than Flow, e.g. things like Definitely Typed, and I think that's become a feedback loop (i.e. more people are interested in TS because it already has a bigger community and more to offer, and thus it has as bigger community and more to offer...)

It probably didn't help that it took a long time for flow to be usable on windows.

I'm sure the fact that flow is considered more tired to react while typescript is considered more agnostic helps as well (I've not explored flow so I don't know whether it is tied to react or not but I do think that's the impression).

I don't think Flow is tied to React at all, except that the default create-react-app includes it as an option.

It does have built in type definitions for React, where as all other libraries you probably need to use flow-typed (similar to definitely-typed in TypeScript).

So it does kind of have React integration, but it's pretty loose - you can use it with any other framework, and there's nothing obviously React-specific about the language.

Edit: See https://flow.org/en/docs/react/types/

It's very tied to the react / facebook ecosystem.

Nuclide for atom was the official release by facebook for supporting flow + react, and now you have Atom-IDE which is optimized for react + immutable.js + flow.

Plus the facebook guys are avoiding VScode like the plague and focusing entirely on Atom. Which now also comes with the BSD+ licence.

"Plus the facebook guys are avoiding VScode like the plague" Not true.

> I'm surprised the author thinks that Flow is more popular amongst the React community than Typescript. I hardly ever hear about Flow, and I work with React and follow it's development.

Agreed. Perhaps the thought that Flow is more popular in the React community comes from people who are not using either Flow or TypeScript? In my experience, I rarely ever see Flow being used in the wild.

Another metric we can look at to estimate popularity is the number of questions on StackOverflow.

Flow has 1K https://stackoverflow.com/questions/tagged/flowtype

TypeScript has 37K https://stackoverflow.com/questions/tagged/typescript

Also looking at NPM downloads this month:

Flow has 1M https://www.npmjs.com/package/flow-bin

TypeScript has 7M https://www.npmjs.com/package/typescript

The goal of Flow was apparently to be able to add types to some parts of the code while leaving the rest of it unchanged, this to me was confusing, because at that time, you were already able to do that with TypeScript.

Over time the argument in favour of Flow became the following: it has a "sound" type system, which means it produces better results in some extreme cases where TypeScript fumbles. I didn't seem to ever hit those corner cases, I just enjoyed the fact that TypeScript had a more robust type system.

Next argument was: Flow is just a linter that strips out the type annotations. Most projects that use Flow use a transpiler, which renders the linter argument moot.

As of today, I don't know of anything that you can do with Flow and cannot do with TypeScript, the reverse is not true though.

Unless I'm missing something, it seems that Flow's existence is based on tribalism rather than rationality, the Angular team realised that if there is already a project out there that covers 99% of their needs, it might be better to just work with the project instead of reinventing the wheel, Facebook seems to have been ignorant of that. Facebook developers seem to have a tendency to just re-invent the wheel instead of collaborating, see Yarn, I'm not saying that they are wrong in doing so, there is a chance that they might be on the right, however I don't feel that is the case when it comes to TypeScript.

> Unless I'm missing something, it seems that Flow's existence is based on tribalism rather than rationality

This is my impression as well. The Facebook employees I see on Twitter seem like super-smart people, but unfortunately they also seem to have a degree of arrogance and aggressiveness about how their tech is superior to everything else, which they often express by trash-talking the "competition".

In fact, a lot of the Flow / React / Yarn, etc. community seems vaguely cult-like, with a cabal of Facebook/ex-Facebook employees as its leaders, and an implicit (or explicit) contempt for anyone too stupid to recognise their righteousness. That alone makes uncomfortable enough to avoid using any of these projects when I have the option not to.

This has been exactly my experience as well. The "sound" type system almost never makes a difference beyond blog post examples. TypeScript is incredibly pragmatic and clean.

I'm a huge Flow fan, and picked it over TypeScript because at the time I didn't like the idea of:

- Switching everything to .ts and .tsx files

- Switching a lot of tooling (TypeScript's built-in ES6 transpiler instead of Babel, tslint instead of eslint, etc.)

- At the time, TypeScript's types were nullable, Flow's were non-nullable, which makes a huge difference to me

- Given that TypeScript is a transpiler along with a static type-checker, it's not always easy to tell which features are going to have build-time vs run-time effects (e.g. private properties, property decorators)

That said, some of the errors from Flow can be incredibly confusing, and even with the latest versions I feel like there's improvement which needs to be made here. This (in my view) is the number one thing it needs to drive adoption.

I went through a similar process and chose TS > Flow.

- Renaming to .ts and .tsx is nicer than adding comments, because it integrates better with tooling (compile all files that end with .ts) and it's easier to see at a glance what's ported

- You can always compile TS to ES2018 and run that through Babel, if you like. TSLint -> ESLint is indeed a change, though you can continue to use most of ESLint for TS [0]

- As a rule, TS is compile time only. There are a few exceptions, but that's almost always the case.

For me the advantages of TS are:

- Huge library of community written typings for JS libs

- Mapped types

- Full support for literal types

- Read only types

That said, I really like Flow's co/contravariance annotations, and the corresponding $Supertype and $Subtype functions. That, and nominal typing can be really convenient (coming to TS soon, hopefully).

[0] https://github.com/eslint/typescript-eslint-parser

> That, and nominal typing can be really convenient (coming to TS soon, hopefully).

I think you meant structural typing? TS was always nominally typed. I searched for a bit and it looks like TS also supports structural typing with explicit interfaces, and I think Flow tries to infer such types? I don't use either one, so I'm not sure about the details.

TS is structurally typed. You declare the fields you expect on a type or interface, and as long as an object has at least those fields, it will typecheck. Nominal typing would mean that you could declare type A and type B with identical fields, but if something is declared as A, it cannot be used in place of B.

TS has a strange workaround to get nominal typing for now:


That's interesting - I'm almost sure last time I checked (possibly a couple years back) TS used nominal typing. Do you know if this changed at some point, or is it just my memory being bad?

TypeScript has used structural typing since the beginning. Classes used to be nominal, but changed to structural (except for classes with private fields) at some point.

> Classes used to be nominal, but changed to structural

Ah, ok, makes sense. I think I was last looking at TS around version 1.1 or something like that. Thanks!

> As a rule, TS is compile time only. There are a few exceptions

Sorry just for my information: which ones are those?

I'm pretty sure generators need a runtime component. TS supports them down to ES3. Async/await gets transformed to generators too afaik.

The typescript compiler is a type checker and a cross-JS-version transpiler in one. Runtime code introduced to support generators in lower ES versions isn't exactly the same as the type system needing a runtime component. It's more like "the Babel part" which is included in TS.

I personally don't think it's an attractive part of TS; it's confusing, and it's just duplicating efforts that Babel already does best. But that's just me.

> Given that TypeScript is a transpiler along with a static type-checker, it's not always easy to tell which features are going to have build-time vs run-time effects (e.g. private properties, property decorators)

This is a huge part of why I tend to prefer Flow for my projects these days as well.

I really value the fact that Flow is just a thin layer of static type annotations you place on top of your spec-compliant JavaScript, and none of its features have any chance of introducing unexpected runtime behavior.

Also, I'd like to add that using Flow with Babel transpilation targeting a ES20xx preset largely guarantees that the source code you're writing is valid spec-compliant JavaScript that can run without transpilation one day (requiring only a dead-simple type-stripping transform using something like https://www.npmjs.com/package/babel-plugin-transform-flow-st... or https://github.com/flowtype/flow-remove-types), and I've had great success with simply dropping all/parts of the transpilation step as the features I use start to become supported in node/browsers/react-native/electron/runtime-polyfills/etc for apps where I don't plan on supporting browsers more than a few versions behind latest, which has been an absolute godsend for debugging in both development and production.

I highly encourage people to try it out on a project where they can afford to do the same (i.e. for packaged projects where you have control over the runtime environment like Electron or React Native, or for web projects where most of your users happen to be also web developers). It's really been a breath of fresh air after dealing with all sorts of subtle transpilation induced bugs/edge-cases.

To be clear, I'm not trying to bash TypeScript, because it's an awesome project, with top-class tooling that has attracted an amazing community around it. I just wanted to remind all the people mindlessly shouting "TypeScript has won" into their own silos, that Flow is also a great type system, that just happens to be designed with a fundamentally different set of trade-offs in mind. That alone doesn't make either system better or worse than the other, but it does mean there are use cases where Flow can excel over TypeScript and vice versa, and that you should carefully consider your project's needs and what characteristics you value in a type system before simply cargo-culting one or the other.

To be fair, one can also stick to .js files and use TS in checkJs mode, in which case it uses jsDoc comments to add types information, so there is no extra step to strip types.

The downside is that a few features don't have a jsDoc equivalent. But it would already catch most of the things you'd use a type checker for, without the hassle of going full Typescript: you could even completely remove typescript from the project and it would still work given they're just JS comments.

Right, that's a great point. If the set of features that aren't supported in the jsDoc equivalent are the same set of features that end up requiring runtime transforms, then I can picture this to be an excellent way to use TypeScript the same way I do with Flow (which also supports a comment-mode syntax, but it doesn't have as compelling a use case in Flow since the standard syntax doesn't require any transformations to begin with).

This is possible with Typescript too with Babel 7. See my comment here https://news.ycombinator.com/item?id=15236089

Thanks for bringing that to my attention!

That sounds super exciting. I'm definitely going to have to give that a shot once it's ready.

Flow's excellent React Native support has also been a large part of why I've mostly been working in Flow-land these days, so I'm glad to hear TypeScript will soon become a first-class citizen in that ecosystem as well.

EDIT: As a follow up question, please correct me if I'm misunderstanding anything, but from what I've gathered so far, I suspect that the new babel-preset-typescript can't quite do _just_ type-stripping can it? Since some features in TypeScript have runtime implications, those would still have to be transformed as opposed to simply stripped, correct? So it looks like that fundamental difference between TypeScript and Flow remains in tact, but it's certainly still a huge leap in usability to be able to adopt the Babel toolchain as a first-class way of building TypeScript projects. Huge props to the Babel and TypeScript teams for making that possible!

> I suspect that the new babel-preset-typescript can't quite do _just_ type-stripping can it? Since some features in TypeScript have runtime implications, those would still have to be transformed as opposed to simply stripped, correct?

I'm quite new to Typescript myself so I really don't know. At least I'm not aware of such features and don't think this Babel feature would make much sense if there were any?

EDIT: I think some of the runtime features are just TS doing ES6 to ES5 compiling. Such as "for of" loops, generators etc., but since those are just ES6 syntax they can be handled by other Babel plugins/presets or even by modern browsers directly.

The two most obvious examples I can think of off the top of my head are features like Enums and constructor param visibility settings. Both must be transformed to retain their runtime properties, and both don't exist in any ratified ES spec. Luckily enough they both also happen to have fairly straightforward mappings to their respective JS implementations, and once you know that they do introduce runtime behavior (and it's fairly easy to notice that they do), you can simply avoid them, so the practical impact of these more obvious cases can be limited.

More troubling cases do exist though. I vaguely remember once coming across some obscure runtime behavior for decorators where they attach runtime metadata that's supposedly used for type reflection, which is a runtime effect that's definitely not immediately obvious or intuitive. This and other potential obscure edge cases like it, some of which may exist in TypeScript today and some of which might be introduced in some future version, are part of what makes Flow's focus on providing trivially removable static typings on top of spec-compliant JavaScript so attractive to me (in addition to opening up the option of minimizing the surface area of your transpilation step or skipping transpilation altogether).

Thanks. Here's the documentation about the enum issue https://github.com/babel/babel/tree/master/packages/babel-pl...

I hope that in future Typescript would take the same approach as Flow and just focus on being a good type checker on top JS.

Flow's tooling was a nightmare last I tried to use it. It seems custom built for a very specific purpose -- incrementally adding types to an existing legacy codebase. Typescript's tooling works seamlessly with webpack/babel/etc.

npm install --save-dev flow-bin babel-preset-flow, add "flow" to the presets in .babelrc and it just works, at least for my projects.

A much more typical experience is to do those 2 steps, and then spend a bunch of time digging through github issues to find the right ignore/suppression incantations to add to your .flowconfig so that your dependencies (including all their transitive deps...) don't break your typechecking. Admittedly this gets easier once you've done it before and know a few reference .flowconfigs to copy/paste like React[1] or babel[2], etc. But this shouldn't be necessary at all. It's been an open issue for 2 years [3].

Less important, but you also have to add /* @flow */ to the top of every single source file. Sure its handy sometimes for existing projects, but it makes little sense for new ones and has also been an issue for years[4].

[1]: https://github.com/facebook/react/blob/65b9ad94aaf62eb61b7b3... [2]: https://github.com/babel/babel/blob/634c750558e5ce149b879b66... [3]: https://github.com/facebook/flow/issues/869 [4]: https://github.com/facebook/flow/issues/284

This has been my experience as well. I used to think configuring tsconfig was more work than I wanted, until I started using Flow in a project and had to babysit .flowconfig. It's hell and adding any dependency can break it in confusing ways.

The fact that flow-bin is a binary which runs as a separate process is the problem. To integrate it with webpack you need to use hacky plugins which are constantly querying the flow server for type errors. With typescript you just use ts-loader and you're done.

I tried Flow 3 times and was always severely disappointed. It's just not as good as TS if you care about type soundness (both are unsound, but Flow just tries too hard to make compromises for mixed codebases) I always found tons of type-checking bugs in Flow, which is a deal breaker for what we're doing (100% type coverage)

Have you tried https://reasonml.github.io/ ?

Only a bit. I really like ML languages. The issue is that the ecosystem is still in its infancy.

I'd recommend keeping an eye on it; it's growing very fast.

After using both, TypeScript feels more natural and clean. Flow adds too many syntax deviations that I generally dislike.

TypeScript works amazingly well with React. Also, it's great only having 1-2 build dependencies rather than 10+ Babel plugins.

Nice article. A little meta-study and then some practical usage compared.

Facebook is also working on ReasonML (a new front-end and some tooling for OCaml/BuckleScript) that compiles to JS and has strong typing. Stronger than either TS of Flow has.

I think in the long run ReasonML is a better approach: the underlying language (OCaml) is carefully designed, where JS seemed to have "happened".

Other options that have even stronger typing are Elm, PureScript and Haskell/GHCJS.

Here's a great article describing all the promising projects in functional/strongtypes front-end land:


Integration with a contract system like Clojure Spec is one of the best features still missing in current type systems. Having that would get best of the both worlds and allow better interaction with untyped code. Racket has this currently.

I like Typescript. But wish it had exact types like Flow. This leads to not being able to type a simple Algebraic Data Type with complete precision.

I think the reasoning given on the github page for not having exact types(involving how it plays with intersection types and union types) has a bug. One can assign T & U to T even when T is exact(exactness of T ensures U wont introduce extra properties), and assigning T to T | U should be fine when U is exact(For a user to determine if a T|U value is T or U, they will have to check whether a property in T exists, not U).

But this is a very small issue.

I'm a bit skeptical of type declarations that are not formally linked to a specific version of the code they describe and cannot be considered to be commitments made by the author of the code.

It's yet another layer of organization and complexity that we need to keep track of on an already incredibly convoluted platform.

Neither TypeScript nor Flow force you to use third party type declarations, but using them seems to be strongly encouraged.

We'll see how problematic this issue turns out to be as these ecosystems evolve.

What are your options though? Don't use third party code? Use third party code with no types along with your typed code? The unofficial types might have some problems (which I've yet to be bitten with yet) but it's much better than nothing.

I'm not convinced it's necessarily better than nothing. Introducing this whole new layer of complexity, potential breakage and maintainance issues is a trade-off. It could go either way depending on many factors.

Another option is to use a proper statically typed language where that is feasible.

Choosing between TypeScript and Flow I would keep an eye on how each of these ecosystems deals with the issue of third party type declarations and versioning.

And if one of these languages gains support by library authors so that we don't need third party types, that would be a strong argument in favor of that language for me.

To get the benefit of static typing in the browser, it seems more strategic to use something that's actually a meaningful departure from JS (Elm, Scala.js, PureScript, ...) rather than JS as viewed in a warped mirror.

You don't want to be fighting to change the fundamental nature of something while being crammed in the trench with it.

> I'm not convinced it's necessarily better than nothing. Introducing this whole new layer of complexity, potential breakage and maintainance issues is a trade-off. It could go either way depending on many factors.

I'm not saying they're perfect but they're practical. I've used numerous libraries with TypeScript using third party typing now and haven't come across any major issues yet.

If you can use a proper statically typed language with libraries then that would be preferable but is that a realistic option? Right now, TypeScript seems like a practical and realistic option to me.

It's no competition for me if I have to pick between plain JavaScript + third party libraries vs TypeScript + third party libraries with maybe slight inaccuracies in their types. For the latter, it's not much difference to coping with library bugs.

Am I missing something with compile-to-javascript languages, or does this kind of heavyweight tooling and build system preclude most on-the-fly repl/console use for development? I'm far from a professional webdev, but have been attacking it recently with the goal of shortening my idea-to-implementation time for side/portfolio projects (I'm tangentially in ops at a tech company now, but want to move into programming).

Coming from a lisp background, the immediacy of the JS console in the browser seemed like a huge win, and I can't really imagine javascript-heavy webdev without using https://github.com/skeeto/skewer-mode or something similar, or at the very least heavy use of the browser's javascript console.

Don't you give up a lot of efficiency/speed when you compile to JS instead of using JS directly? Or do I misunderstand the trade-off and the benefits of static typing are enough that it's acceptable to have a separate build step after every change, like you're a C++ programmer?

I don't know about Flow, but in Typescript you can still fire up a REPL and play around. The difference is that the typechecker validates every command you run. This is enough for small experiences, e.g., when you want to validate an algorithm. But yes, in the case you want to rerun your application to test your changes, the feedback cycle is a bit longer. But I find acceptable considering that static-typing makes refactoring significantly easier and less risky, which is important when working on large projects.

How do Sherpas get around without canoes? How do Amazonians stay warm without an Igloo?

I can't speak for Flow and Typescript, but I've been teaching myself Elm after a decade of JavaScript development. Elm has a very strict static type system, compiles to JavaScript, does have a REPL, and isn't readily debuggable like normal JavaScript.

Like any comparison of programming languages, you come to rely on features F, G, and G because your usual features X, Y, and Z don't make as much sense in the new language.

Elm famously promises that if a program will compile then it will run without runtime errors, and delivers on that promise. As a consequence, more time is spent in conversation with the compiler in exchange for never having to step through a program and see where things went wrong. A working program just "snaps together" and lets you safely refactor or move on the next feature. The feedback loop in Elm is very fast because you don't have to run your program and play with it in order to see it fail.

As far as I can tell the Elm REPL can't analyze types in the way that the compiler can, so it's not really useful except to experiment with basic functions and values.

Most JavaScript projects I work on these days have some kind of build step, whether that's limiting or minifying or transpiling ES6. So no difference there, except that the Elm tooling is nicely integrated and doesn't require as much futzing around.

All this to say that a step through debugger might only seem essential if your program can be run in ways that require debugging.

Typescript is written in itself and compiled to JS. You can use Typescript directly in the browser if you have the inclination. There's still speed tradeoffs, but you can even play with a Typescript REPL (http://www.typescriptlang.org/play/index.html).

There's a growing set of tools in the build tooling space called "Hot Module Reloading" (HMR). Webpack and JSPM/SystemJS both have picked up HMR tooling of different capabilities. HMR is very similar, from what I can tell, to the skewer-mode example you have posted: HMR tools watch for file changes, rebuild the bare necessary for those file changes, and via websockets between development server and browser communicate "live" reloading of modules as you work.

The work in HMR space is pretty impressive; I've started to rely on it in some webpack-built projects lately.

That said, "build step after every change like you're a C++ programmer" is a workflow that has survived a long time. There are some developers that prefer the comfortable routine of that workflow.

As a professional web developer who uses TypeScript (disclaimer: MS employee, not on the TypeScript team), I don't find that it impacts in-browser debugging. TypeScript has the ability to generate map files, but we don't use it because issues with our tooling. I don't miss it though, because the generated JavaScript is pretty close to the TypeScript (we target ES5, if you can target ES6 the mangling is even less). Once you learn the common patterns (methods get mapped onto the prototype, fat arrow functions get compiled to regular functions with a _this variable) it's pretty straightforward to debug in the browser.

The dev inner loop is maybe a little slower with the compile step for us, but it is possible to use TypeScript's automatic compilation with webpack and Node and all the latest hotness and get automatic build/deploy/refresh (see Office Fabric: https://github.com/OfficeDev/office-ui-fabric-react)

It hurts the REPL experience a lot. You can still open the Console and execute JS in the context of your application, but you'll end up working in the transpiled JS, which might look very little or nothing like the source code you've been working on. It's annoying to the point that I don't bother doing it often any more. I think ClojureScript might be an exception to this, though, so if you're a lisper that's probably something you'd want to look at.

I don't find it makes much difference. If I get any runtime errors, you can add breakpoints into your code and the compiled TypeScript looks very similar to the JavaScript most of the time, plus you can use sourcemaps. The test code you type into the console doesn't need to be written in TypeScript either. The build step going from editing in an IDE to the code running is only a couple of seconds maximum as well.

Getting more errors to appear in your IDE at compile time compared to in the console speeds you up way more than any slowdown you'd get too e.g. being told a variable could be undefined at compile time is much faster to fix than having to wait for a runtime crash, you having to track down the cause then hoping you've fixed it.

I use WebStorm and debug TS inline all the time. There's definitely a lag from doing straight JS in dev tools, but I'll happily take the extra hit for the benefits of a transpiled language. Raw JS can be a pain in the neck to debug if the code you're working through is poorly written. You can still write bad TS, but it's less likely.

Is this normal if flow show many error list from node_modules library. How to filter ignore from library? Flow - reactnative - vscode

Given how close these two things are, I wish the field would settle on one - either one, really - so that we could embrace its ecosystem, and move on with more and better libraries, tooling etc for the winner.

I don't think this will happen, because Typescript now has a very large user base, and Facebook will stick to Flow.

However, I don't think flow is going to survive React, because it's only used there and internally at Facebook, while Typescript is used successfully with React, Angular, and basically everywhere people need typechecking outside of React (Typescript has definition files for most libraries with significant users)

One other interesting thing is that Facebook is even internally cannibalizing itself, by developing and promoting both Flow and ReasonML as a way to develop web apps.

From the outside it really seems there are 3 ecosystems, a large one (typescript) und 2 others (Flow and ReasonML) that are mainly used for parts of facebook.

If the end result is "Facebook is using Flow, everyone else is using TS", I would consider it settled in favor of TS.

Competition helps spark better ideas though & as long as you use one of them, you're JavaScript will improve greatly.

I'm of the belief that well written JavaScript is safe to use without semicolons but typing JavaScript without a type system is like running while dressed up as Edwards Scissorhands.

Competition helps spark better ideas by having a winner - that's how you (presumably) know which ideas were better.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact