TypeScript at Slack
slack.engineering
slack.engineering
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>
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;
https://github.com/Microsoft/TypeScript/wiki/What's-new-in-T...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: declare module 'some-big-node-library/**/*'
declare module '**/*.css'
declare module '**/*!text'https://blogs.msdn.microsoft.com/typescript/2017/04/10/annou...
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.
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'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.
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.
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.
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#.
but that's not really Microsoft's fault
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.
This guide [4] looks pretty good, too.
[1] https://github.com/redux-saga/redux-saga
[2] http://stackoverflow.com/a/40027778/304706
[3] https://hackmd.io/s/H1xLHUQ8e
[4] https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
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.
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.
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.
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].
[0] https://github.com/markerikson/react-redux-links/blob/master...
[1] https://decembersoft.com/posts/what-is-the-right-way-to-do-a...
[2] http://blog.isquaredsoftware.com/2017/01/idiomatic-redux-tho...
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.
How so? Isn't JS-with-Flow just JS with specially formatted comments?
But the "default" is annotated JS which is not dissimilar to how TS operates.
I prefer Flow's syntax and if it wasn't for the annoying "you have to run a server to check code" thing... I'd use it a lot more
Which is sadly important - for something so optional.
Sidenote that Flow does allow specifying types through comments but this is a bit of a second-class feature.
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.
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;
}
which is terrible to both write and read.> 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'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.
~: cat test.ts
class Foo {
foo = () => console.log('Foo!')
}
~: tsc --target es6 test.ts && cat test.js
class Foo {
constructor() {
this.foo = () => console.log('Foo!');
}
}
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.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.
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.
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.
Read the rest of this thread, that is the point at hand. I'd generally suggest doing that before jumping in.
https://tryflow.org/?code=Y2xhc3MgRm9vIHsKICBmb28gPSAoKSA9Pi...
You get no errors.
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.
[1]: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Desi... - goal 6
This is literally exactly the same amount of true for TypeScript as it is for Flow
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.
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.
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!
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.
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.
I don't understand why this myth persists.
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.
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.)
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.
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.
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.
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).
Give it a try! Ping us if you need to: https://github.com/facebook/reason#community
Edit: Never mind, you're referring to my complaint about the OCaml toolchain. Carry on :D
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.
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.
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.
DT is "DefinitelyTyped", a github repo that consolidates type declaration files for open-source packages on npm.
Ironically, given the above comment, its tagline is:
> The repository for high quality TypeScript type definitions. (emphasis theirs)
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?
With Typescript, you have to write custom Type Guards functions, whereas Flow is smart enough to infer type
Have a look here: http://djcordhose.github.io/flow-vs-typescript/flow-typescri...
* 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.
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.
Here's the only issue I found, which is now closed: https://github.com/flowtype/flow-typed/issues/247
Yes, the React Native packager depends on Babel, and uses a react-native preset. When you start a new project, you get this default .babelrc:
{
"presets": [
"react-native-stage-0"
]
}
They basically wrote their own version of webpack, to solve some performance problems and make development as fast as possible.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.
[1]: https://github.com/flowtype/flow-typed/issues/16
[2]: https://github.com/styled-components/styled-components/blob/...
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.
[1] https://www.youtube.com/watch?v=AslncyG8whg&feature=youtu.be
> TypeScript has larger community.
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.
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 :)
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.
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.
https://www.typescriptlang.org/docs/handbook/advanced-types.... https://basarat.gitbooks.io/typescript/docs/tips/nominalTypi...
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 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).
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 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.
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.
This is also how people used async before it had official support from the typescript library.
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]
That's why there are stages and you should use at least stage 2 (draft) https://babeljs.io/docs/plugins/preset-stage-2/
* - [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]
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.
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.
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?)
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 excludedThis says "either an array of Foo or an array of undefined", right? Not "either an array of Foo or just undefined"?
Foo[] | undefined[] means either 1) an array of Foo, or 2) an array of undefined.
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.
ReactDOM.render(
<Start />,
document.getElementById("content")
);
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.This pattern really isn't hard and if it saves you from one "undefined is undefined" then it was worth it.
const item = document.getElementById("content");
if (item == null) {
console.log("Render container missing");https://github.com/technion/awesome-sec-audit/blob/master/as...
If you insert the element directly in line 25 you'll get:
error TS2345: Argument of type 'HTMLElement | null' is not assignable to parameter of type 'Element'.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).
- 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.
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.
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".
> 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.
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.
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.
function test ({param1, param2}: {readonly param1: string, readonly param2: number}) {
return
}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.
> 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.
One of the points was talking about React Native vs Electron. What are your thoughts? Why did you guys go with Electron?
But I would switch to all-scala if it ever had a dev-friendly 100% integration strategy.
https://www.reddit.com/r/programming/comments/64e6x7/typescr...
Brad Green already posted a follow-up post on the omission of Dart on his slides: http://angularjs.blogspot.dk/2017/04/official-languages-at-g...
(I work on Dart.)
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?
There are millions(trillions?) of lines of code out there that is maintainable and dynamically typed.
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 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.)
There are a few valid arguments in favor of dynamic typing - but that isn't one of them.
> Or, How I Learned to Stop Worrying & Trust the Compiler
So revolutionary. Who knew that compiling code has advantages over interpreted scripts.
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.
Am I right or am I right?
My guess is those were not an engineers, but script kiddies / code monkeys.
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.
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.
- 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.
TS has been worth it to me, even if once in a while the compiler is too fussy like you say.
function foo(a, b, c) {
g.param(String, a);
g.param(Object, b);
g.param(XMLHttpRequest, c);
/* stuff */
g.return(String, bar);
}
Seems like the main benefit to using TypeScript is that it can tell you if you have poor types during "compile" time, right?I guess the question for me is, is TypeScript superior than the above pattern?
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): string1) 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.
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.
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.
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?
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.
Kind of funny to read this article, after just reading that Electron article.
[1] https://github.com/facebookincubator/create-react-app/issues...
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!
Functions in Coffeescript: -> =>
Functions in Javascript:
var myFunc = function(){}; function myFunc(){} var myFunc = () => {}; in objects: myFunc: function(){} in classes: myFunc(){}
Inconsistency in code is a recipe for bugs.
They also need to crackdown on the Facebook app.