1. Both TypeScript and Flow are gradual type systems. They both explicitly allow escaping the safety and coverage of a type system, either to allow easier interop with existing JavaScript packages or to allow existing JavaScript codebases to incrementally adopt types. So there are always holes in which errors are reported, regardless of whether they had to silence some explicitly or not. By measuring the extent, they have a yardstick against which they can drive further type adoption.
2. Repeatability is the only way to do large code migrations. Write the steps in a script, run it, find the bugs in the script, fix the script, and repeat. With 300k lines of code no doubt they have dozens or hundreds of people committing daily. So a script is the only way to sneak in during off-hours, get something in that doesn’t race to conflict with someone else, and land the change. A long running, manually crafter branch here would not work—it would effectively operate as a fork of the codebase for the entire duration of the migration, with all the downsides that a fork entails.
Kudos to the team; this is a very impressive feat!
https://www.typescriptlang.org/docs/handbook/advanced-types....
Intersection Types - An intersection type combines multiple types into one.
Union Types - A union type describes a value that can be one of several types
Type Guards - A type guard is some expression that performs a runtime check that guarantees the type in some scope.
Nullable types - compiler level safety for "can be a null " implication of any type
Type alias - as the name suggests
String literal types - Union type of few string values
Numeric literal types - Union type of few numeric values
Enum Member Types - enum members have types when every member is literal-initialized
Discriminated Unions - You can combine singleton types, union types, type guards, and type aliases
Index Types - you can get the compiler to check code that uses dynamic property names
Mapped Types - Transforms each property in the old type in the same way to create new type.
Conditional Types - selects one of two possible types based on a condition expressed as a type relationship test
https://github.com/microsoft/TypeScript/issues/31983#issueco...
Overall, I'm very happy to see more and more teams move to TypeScript as a direct consequence of its Babel 7 support. TypeScript makes more sense as a pure type checker and not as a full blown transpiler.
It's also interesting to see that their type coverage increased from 66% to 86% (ours increased from 88% to 96%). This pattern is probably because of better third party type definitions.
I still prefer Flow's Type Inference and philosophy over TypeScript's, but in practice TypeScript is much better pretty much any use case I can think of.
[1]: https://davidgomes.com/porting-30k-lines-of-code-from-flow-t...
type A = { readonly prop: number }; type B = { prop: number };
function func(f: B) { f.prop = 20; return f; }
const a: A = { prop: 10 }; func(a); // no error?
(Closure is a venerable JavaScript type system by Google using JSDoc-like annotations.)
Stop the world migration, automated scripts, manual fixes, lots of ts-ignore/any. And thoroughly worth it.
[1] https://www.lucidchart.com/techblog/2017/11/16/converting-60...
TypeScript just keep getting better and better. I am looking forward to better Google Bazel support for TypeScript to help with monorepos.
Having used both, there are a few features in Flow that I'd miss. I think classes being nominal is a good approach and the ability to declare new nominal types is useful. Otherwise Flow's type system is structural, like TypeScript's. Function parameter type inference is also very nice feature, so I can make simple module- or function-local helper functions without needing to specify the parameter types explicitly. Having a syntax for specifying parameter variance allows for a more sound type system in some areas.
Performance has historically been pretty bad but it's been getting better with every release. The tooling has also seen some improvements after Facebook nuked their own Nuclide-editor project and moved on to endorsing Language Server Protocol and VSCode. It's still far, far behind TypeScript, though. It's also a bit worrying that the community seems to be getting smaller, not bigger, with posts like this popping up.
Flow's Windows support is pretty buggy. We have some team members who prefer Windows as their dev machine and it looks... painful.
Flow supports the upcoming `?.` operator and overall they seem more open to introducing features that are in a development phase and might be changed/deprecated in the future. I guess it's a matter of perspective if that's good or bad, but man I'm going to be sad if we end up making the change and I have to convert all those nice and clean `foo?.bar?.baz` chains into some unreadable multiline monstrosity or calls to some random getter library.
Flow's exact object types [1] are really useful and have prevented actual bugs when used with optional properties. TypeScript's concept of "freshness" [2] does prevent many if not most of these bugs though.
[1]: https://flow.org/en/docs/types/objects/#toc-exact-object-typ...
[2]: https://basarat.gitbooks.io/typescript/docs/types/freshness....
It's funny because Typescript started out by trying to get ahead of a lot of features and "settling down" to trying to stick to (mostly) only TC39 Stage 3+ features has been a maturation that has been good for the language. It's interesting that Flow seems to be moving the other direction.
A benefit to making it easier to pipeline Typescript inside Babel is that it is no longer entirely on Typescript to transpile every possible wishlist language proposal. This is also why a lot of people preferred Flow because you could just slot Flow checking before or after certain transforms. Typescript is getting better about fitting into the middle of a Babel transform stack so that you might have some basic preprocessing steps of Stage 2 or earlier or non-standards track things that Babel supports before type checking.
(The Optional Chaining proposal for `?.` is currently in Stage 2 in TC39. Indications seem to be that at least some of the Typescript devs are ready to champion that feature in the very minute it hits Stage 3.)
My impressions are mostly positive in the sense that if you are doing JS, you are better off doing TS. The tooling is great and you can start with simple changes that almost immediately start giving clear benefits in terms of typing related warnings and other improvements. Typescript is minimally intrusive in the sense that all js is valid ts and you can gradually improve it by adding type annotations and addressing warnings.
The benefits are a vastly improved safety net at a very minimal cost, smarter tools, and more confidence that a given piece of code will not break with some entirely preventable error (like an NPE). Excluding whole categories of bugs is a good thing. For new code, I consider it a no brainer. Most new projects seem to default to using typescript so I guess more people have come to the same conclusion. Lots of upsides, no real downsides that I know off. You'd have to be pretty stubborn to opt out at this point. For older code that you still care about, migrating is a good investment as well: you will improve the code. Any other code you probably need to get rid off anyway.
That being said, I believe typescript is merely a gateway drug. Typescript is great and you definitely should use the strict mode. But even in the strict mode it still inherits a lot of cruft from javascript and this makes life needlessly hard. Other languages don't have this problem and the progression from the js/ts ecosystem to other things is very obvious with some younger full stack engineers I've known for a few years. Go and Rust seem particularly popular lately. And even Kotlin seems to be well liked (big fan myself).
Better still, a lot of these languages are coming to the browser (via WASM or transpilation). Inevitably, some projects will start moving away from defaulting to the js/ts ecosystem for frontend work. Right now you'd be a very early adopter but things are improving rapidly and there are some early adopters. I played a bit with kotlin-js recently and while it still has lots of rough edges, it actually works quite well. Not quite a drop-in replacement for typescript just yet but most of that is related to consuming javascript from kotlin; which I'd argue is short term needed but long term undesirable and likely to become less important as native kotlin frameworks emerge (e.g. kvision is a popular one). Tip, parcel recently added kotlin support; works without extra configuration even.
> Better still, a lot of these languages are coming to the browser (via WASM or transpilation)
I think this has always been a concern - CoffeeScript had its moment in the sun, then the good parts got merged into JS and it died out. We'll see if that happens again.
WASM concerns me, though, because of the utility you outline, which doesn't actually serve the end-user in any way shape, or form. Much like we're seeing tiny webapps made with React (and requiring browsers to download and parse the accompanying runtime), I worry we're going to see sites using e.g. Kotlin in WASM simply because that's the developer preference, totally ignoring the fact that it means every user is going to have to download a Kotlin runtime and garbage collector despite there being a perfectly good JavaScript one sitting right there.
No. Some good parts have been merged, but so many good parts will never get to ESxx or Typescript. Most dev's just don't see it because they do not know Coffeescript well enough. Compared to Coffeescript, Babel is a total mess with all it's options/plugs config etc..
I rarely have type issues in JS, Python or Coffescript. I do have type issues in Typescript though. I fix that with 'any', just like my collegues. A Typescript codebase is about 2x bigger than a Coffeescript codebase, that means about 2 times more chance for bugs. But it's totally amazing to see the Typescript proponents considering the language to be a godsend. I moved from C/C++ to Javascript to get rid of static typing, it's part of my love for JS, but now that joy is being destroyed by static type enthusiasts.
I've never worked in a pretty Typescript codebase ever, same with JS, so many bad constructs, bad naming, bad architecture, etc, etc.. IMAO the real problems with codebases cannot be fixed with Typescript, the problems are way too big and complex for that.
I still don't understand why JS dev's that crave for types don't do Elm or Purescript instead of Typescript.
WASM is currently indeed bottlenecked on the lack of GC. This is being worked on. I expect a lot of progress over the next two years that will gradually remove most of the obstacles on this and other fronts. None of these are fundamental issues; it's just a matter of things not being perfect yet. Despite this, there's already a lot of early adoption. But I agree that Kotlin on WASM is short term not ideal. In the same way C#/Blazor currently only makes sense for enterprise application where download size is less of a concern. Rust does not really need GC, which is why is a popular language for this already.
As far as bloat is concerned; react is actually pretty horrible. I've seen simple react applications go over 1 MB for no good reason. I'd say the react ecosystem is actually a main driver for people wanting to have some alternatives. I actually prefer more lean approaches. Vue.js seems nice and I'm aware of a few nice lightweight dom abstractions (e.g. redom is nice).
> The benefits are a vastly improved safety net at a very minimal cost, smarter tools
That's entirely subjective. As far as tooling, I get the impression from my coworkers and what I've seen online that people that love TypeScript love big bloated IDEs. They love having their IDE tell them what to do. And, personally, I find their usage of IDEs to be a crutch that prevents them from transitioning from a plateau of mediocrity to being a great developer. They don't understand the code. They merely throw things together that match the types that their IDE tells them, like LEGOs. Then they spend hours trying to figure out why their code doesn't work.
As far as the cost goes, my experience has been vastly different than yours. TypeScript is killing my organization. For no real benefit. The warnings it produces are for theoretic bugs rather than actual bugs. The warnings TypeScript produces are incomprehensible to most developers. And when they finally quiet TypeScript down, they don't realize they have the wrong types! No one seems to fully realize how easy it is to get TypeScript wrong. Your code gets littered with ts-ignore and "any" types and suddenly you have a mountain of tech debt. Code becomes ugly and difficult to read with type annotations. It's hard to imagine anyone actually winning in this war of attrition between clean, simple, readable code and TypeScript.
If you're doing TypeScript and having an easy time of it, you're most likely doing it wrong. TypeScript is incredibly nuanced.
Management loves TypeScript though. It's a shield for responsibility. When bugs happen (and they still will with TypeScript), they can point to TypeScript as something they tried. They didn't fail the organization, their technology failed them.
This in a nutshell is why world + dog is introducing typescript to their codebases. It obviously won't catch all bugs but it will catch more of them. The alternative of not using it simply inexcusable and the people arguing against it tend to not have a very solid case and indeed focus on what arguably is highly subjective like e.g. your claim that it is "ugly". IMHO JS without types is ugly (opinion) and less safe (fact).
I agree typescript is not perfect; I agree it is super sloppy, actually. Even the strict mode still allows a lot of stuff that you should probably should not do (like slapping the any type all over the place). That's why I call it a gateway drug. If you like the little that typescript does, there are other languages that are better.
If typescript is "killing your organization", you should consider leaving. There are all sorts of reasons for organizations to become dysfunctional. The problem always boils down to people, not technology. I'd argue that given your statements, you are possibly part of the problem and not the solution here.
function foo(bar) {
if(foo.baz == undefined) throw new Error("foo need to have a baz! foo.baz=" + foo.baz + " foo=" + JSON.stringify(foo, null, 2));
}
Typescript could probably detect the bug in the first place if you had used interface or what not, and typed everything. Static typing (and also tests) can however slow you down when you are quickly iterating and re-writing. And at the end of the day when you have a working prototype/MVP, and have added a few manual checks that will throw early if there's a bug. Are you gonna spend your time type annotating it all (or writing tests) or are you going to spend that time marketing ?If the product receive continuous work there will however be a tipping point where tests are needed. And the checks you added will be of help as errors will come early. But when you have tests in place, is it really worth it to spray-paint the code with annotation and make it static ? There are already tools today that can infer most types, and give you auto-completion already.
TypeScript is a hack of epic proportions and every so often the reality rears its ugly head in the form of failed source mapping, version compatibility issues, unexpected types during runtime, poor architectural decisions aimed at pleasing the compiler instead of fulfilling project goals.
TypeScript is a very poor way to model real-world systems because it incorrectly assumes that real-world entities have a fixed type schema. This is obviously wrong. Real-world objects change over time and most things cannot be categorised clearly. A tadpole turns into a frog and learns the ability to walk. Some people are disabled and cannot walk. Some cars have 6 wheels. There is no fixed type schema for anything in the real world; it is filled with anomalies so why should we design systems to model such unrealistic objects? Why not force the developers to account for as many cases and schemas as possible, it's our job!
Disclaimer, I freaking love JavaScript and TypeScript.
> TypeScript is a hack of epic proportions and every so often the reality rears its ugly head in the form of failed source mapping, version compatibility issues, unexpected types during runtime, poor architectural decisions aimed at pleasing the compiler instead of fulfilling project goals.
This just sounds like JavaScript to me. Maybe TypeScript has helped elucidate those problems for you. TypeScript adds some syntax to help formalize solutions to these problems that existed in JavaScript already.
> TypeScript is a very poor way to model real-world systems because it incorrectly assumes that real-world entities have a fixed type schema
This sounds to me like programmer error. TypeScript provides facilities for unknown structures, or structures that have multiple possible definitions. There is the union type for which we can tell the compiler that a value can be of type `A[ or B[ or C[ or... ]]]`. Perhaps even more powerful is optional types. In interface you'd describe an optional field with a question mark, like `{ foo?: string }`. Alternatively, you could use the union type described above, unioned with `undefined`. These structures help you create types that actually do model the uncertainty of data coming into your program. If you're not using these techniques, then you're missing out! Having the type-checker yell at me because I didn't check for the undefined case is a really really cool thing.
> Why not force the developers to account for as many cases and schemas as possible, it's our job!
I would argue that TypeScript provides the vocabulary for doing just that and that JavaScript provides no such niceties. Sure, you provide run-time checks on a piece of datas validity, but there's no system to check that run-time behavior before code gets merged to master.
If you're not running `"strict": true` and annotating your TS code with optional values when data is coming into your program, you might have a bad time.
It ensures internal type safety. If you don't have a lot of complexity on your side (e.g., a large client-side app) that may not be worthwhile to you, but it's certainly a thing it does, and a reason static typing is generally considered to be of value, particularly in large, multiprogrammer and, even moreso, multi-team projects.
As for your third paragraph, we follow some degree of functional programming precepts, which implies we avoid mutability as much as possible, so I can't comment much on the problems of mutating TS. I enthusiastically recommend pursuing immutability though, TS or not.
For example for what you said about "JSON objects received from the API" has no type validation, it doesn't unless you define the types for it. You can write interfaces that defines the API responses and use it across whole code base.
You need to do manual schema validation, just like you did with JavaScript. TypeScript adds 0 value. The type only gives you an illusion of safety, which is worse than no safety at all.
There's a weird impulse out there to try to pretend the limitations of static type-checking don't exist... namely, that it's static. That is, it's build-time checking and doesn't provide guarantees at runtime.
For tightly coupled systems were you control all tiers, you can stretch the value of static type checking by ensuring that changes to back, middle, and front all roll out together. But obviously, you're seriously limiting the scalability of your product and agility of your releases when you do this (you need a command-and-control dev communication structure). If you want static type checking to make guarantees beyond the local component, this is a major architectural commitment. To maximize the "guarantees" of static type-checking, it will affect the topology of your entire product, including the release process. (How much downtime is acceptable per release? What limitations are you willing to accept in terms of distributed scalability? Is it acceptable that user sessions become invalid for a release and how will you handle the UX for this?)
Not saying you shouldn't do it, but go in with your eyes open.
Now, static tools certainly have their uses. But:
(1) type-checking is just one limited case. e.g., go get eslint, turn on almost all the rules, and work with that for a few weeks. After you get over the initial shock, you'll get a lot of benefit from from it and it will last for years.
(2) it doesn't help you with anything external to the source file that's not tightly coupled through some additional control mechanism. (Note that you pay a price for control mechanisms.) So, it's a small solution to small problems. Quite nice. But limited without paying an additional price, which may be quite expensive depending on the other goals of your system.
I don't agree with the previous poster's assertion that it's a useless hack. But I understand why one might feel that way. The utility of static type-checking seems to be greatly oversold.
If you look at a typical call stack - in any language - going from the frontend all the way to the database, there will be hundreds of lines. Two, maybe three of those will be remote jumps.
Every one of those calls is an opportunity for a contract mismatch. Even if static type checking misses a half-percent of your calls, it's still working to enforce 99.5% of your contracts. The value of that is hard to oversell.
That's why I was lead to something like ReasonML because it solved the things I was already trying to do with my front end code (keep my renders in React immutable, minimize side effects, use more functional paradigms, have strong typing), but it did it with a much more powerful functional language, with a world class type system in which only Haskell rivals.
I think this is probably the wrong kind of hubris.
Which leads to my next point, the slowness of writing TS compared to JS. I don't know how you maintain your code bases but from my experience any time a new programmer comes in who doesn't know anything about the code, they'll be from time to time wondering, in their heads or aloud, what the hell is the type of some parameter or why something fails on some weird undefined value bug. There's just so much trial and error with JS whereas with TS I don't have to look up at the broken website to see all the errors hitting me as it's all caught with the compiler. Pretty basic static typing stuff but it all comes down to more time writing code, sure, but less time over time maintaining it. And overall the readability of your code is just night and a day with special emphasis towards young programmers or those unfamiliar with the codebase.
What I think has happened is, that you've been bitten by some weird problem regarding API endpoints and incorrectly assumed your typings would hold with an external data source. That just sounds poor programming (don't you use validation libraries such as Joi?) and frankly, a problem entirely of JS itself that such anomalies would happen. If my API starts returning arrays instead of objects sure as hell I'd be angry too but that's just not how it should work. Not a problem of TypeScript, at all.
About the other problems - haven't faced those myself. Most problems I've had have been with writing the correct types especially when they get complex with generics. Sometimes TSC has been annoying and also exporting types into a single typing file seemed quite laborious last time I tried.
In OOP, passing complex instances to functions across different files is dangerous because the different files may all end up affecting the same instance's internal state and you don't know which file is responsible for what change (and it can lead to conflicting states/bugs). The absence of types in JavaScript tends to discourage this design precisely because it makes it difficult to express those kinds of complex/rigid class relationships.
JS encourages developers to keep each kind of "live" instance in a single file and only return raw data from that file. For me, restricting all instance mutations to one file is the secret to writing good OOP code which has clear separation of concerns.
what do you mean by type validation of JSON objects? If you mean, that you can for exammple pass string to object property defined as number, then I must warn you, that this is problem in all languages (eg. most java json serializers, will throw exception). Anyway if you need to ensure all object properties have correct type, you should write validator/transformer (there are already libraries that can do it for you).
Static typing requires you to express things in a way that is easily formally provable by the type system. It's much easier to write correct code (=working parer) than the correctness proof in a limited type system. This goes for higher order operations on schemas / types too, eg schemas are easier to make composeable than types.
I think fundamentally something deeply wrong with all that, and I don't know when and how we're going actually to fix it. After years of trying, I finally decided enough is enough and started looking for deferentially alternative solutions. I like Purescript and Elm. ReasonML looks promising. Currently, I'm using Clojurescript. It is not a silver bullet, but it is an astonishingly practical choice. I know - it won't work for everyone. The majority would dismiss it almost immediately (mostly for the wrong reasons).
I'm not advocating for it. I'm just saying that I feel Typescript is not that magical pill that makes everything better. If you follow @garybernhardt on Twitter, I think he may feel the same.
Sure the churn can be discouraging and if you wanted to be able to write the same way with same tools to retirement I wonder why you'd even consider doing frontend development. I am quite happy with the tools I use (Typescript, React, Mobx, StyledComponents) and have felt no need to change for something else. They are tools I am very productive with, and all the developers I've worked with have been able to get quickly on track with using them. No huge mental leap from JS to TS as with functional languages like Clojure or Elm.
Although it's my opinion that, JS itself should be eventually be phased out for something better for majority of frontend software. It just has too much old baggage so it would be best to just switch for something new completely. However, there's something mysteriously intriguing about JS in that allows so great flexibility, in good and bad, that not just any language can replace it. But nowadays I don't do much complaining about JS stuff anymore. I have found my sweet spot and I'm mostly just busy getting stuff done and there's things far worse in programming than how "bad JS is".
But I haven't heard anyone take this perspective and I'd be really curious to hear people's thoughts on this idea.
[1] https://sdegutis.com/2019-06-20-considering-removing-typescr...
This is something a faster computer can mitigate. Also I would compare the time you spend guessing what parameters actually are in vanilla JS vs the seconds you lose waiting for a Typescript build. Silicon time is much cheaper than carbon time.
I don't understand how anyone doesn't use Typescript for large projects. Javascript is just too lenient. It doesn't even complain when you're not matching a method signature that you call; you can't even catch these ninja errors let alone explicitly know they dropped on you. There's a lot of value when you have a system that adds more checks and validation before runtime.
We're closely following this discussion so if you have any questions on some of the specifics we're happy to answer!