TypeScript at Google
neugierig.org
neugierig.org
I thought about this for quite a while when we started on TypeScript at Google (I work on this with Evan). I've convinced myself that using a different language cannot solve the problem that we're looking at.
The argument goes like this: if you use a different language than JavaScript for front end development, you're (hopefully) doing it for a reason. That is, you (a) want the other languages semantics (e.g. bounds checks on array accesses, runtime types, method dispatch, you name it), or you (b) might want the programming languages ecosystem - editors, IDEs, etc; but most importantly libraries and frameworks. Most likely, you're looking for a combination of (a) and (b).
The problem with (a) is that the more different the runtime semantics of your programming language are, the more emulation code you need. Emulation code is costly in code size, performance, interop with JS, and often understandability (at some point you will need to debug the output, believe me).
The problem with (b) is that you typically opt into a large ecosystem that was originally written for a very different environment. This was a big issue with GWT: people would pull Java libraries, but those libraries, amazing as many are, were not written for the web or with code size in mind. This meant using a common library like Guava required a lot of engineering effort to keep code size in check. This also applies to WASM, possibly even more so.
These mechanisms work together to make it very hard to hit the sweet spot between performance, developer experience, and interoperability. And ironically, the better you get at the goals you're aiming for (different semantics, different ecosystem), the farther you get away from a working solution.
I don't think it's impossible to achieve a transpile-to-JS language that works really well with enough investment, but keeping in mind the other reasons Evan lists (mind share, existing code base), incrementally improving JavaScript where needed is IMHO the much more promising approach.
This is why the candidates in this space are only the upcoming ones like Dart, Elm, and maybe Kotlin. The other "compile to web" approaches that use more established languages (like emscripten for C++ or GWT for Java) tend to produce larger binaries due to carrying along their ecosystem.
This is restating GP's point, but to say it again, this tradeoff is kind of inevitable -- half the reason to want to transpile is to reuse knowledge and libraries, but then by reusing those libraries you kill your binary size.
(This dynamic reminds me of all the people who hoped they'd be able to reuse their existing web apps on mobile but ended up with bad mobile apps. I think it's possible to make a good web-based app work on mobile but it's often a rewrite from an existing web site, at which point you're often rewriting anyway and might as well use a mobile-native language.)
Since the nature of this "tool" is an extension to the syntax, there is a bit of risk that there will be an conflict with some future JS, but other than that, the 2-factor (same but more explicit semantics, same but fortified ecosystem) analysis seems to show why TypeScript is popular.
So why Kotlin instead of TypeScript?
1. Potentially more static optimization, because Kotlin is designed from the start for static typing. 2. Ability to target other platforms (Android, iOS, desktop) without adding the overhead of a JS runtime.
Why not Scala?
1. Scala's standard library is heavier. For instance, Scala has its own collection classes, whereas Kotlin merely has its own collection interfaces. I assume this is why Scala.js advertises a starting size of 45 KB gzipped for an optimized build. That's not actually very small. 2. On the JVM, Scala fundamentally gets interop wrong in at least one way: Java getters and setters don't automatically become Scala properties, as they do in Kotlin. So idiomatic real-world Scala requires more wrappers.
The one thing that worries me about Kotlin is that it has reflection instead of compile-time metaprogramming (e.g. macros). Wherever reflection is used, it impedes static optimization (e.g. ProGuard, other tree-shaking). Sure, real-world JVM work has to use reflection sometimes, but at least JetBrains should have refrained from providing an API for doing Kotlin-specific reflection, and provided something like macros instead. (Edit: And yes, the Kotlin reflection API is implemented in the JS back-end. That was a mistake.)
But, over time GWT became a hindrance rather than a help. The DevMode plugin stopped working as of FF27, and I had to keep around a copy of FF24 just to debug the client. The entire app had to be recompiled every time I made an edit and refreshed the page, wrapping JS libs to expose them to the Java code was a pain, and no one else on the team I moved to had ever worked with GWT. The discussion around this notional "GWT 3.0" didn't help either - it sounded as if half of the technologies around GWT would be removed, like GWT-RPC, but at the same time all the threads about it have been saying "well, J2CL is still internal to Google, we'll get it out eventually". Really uncertain future there.
I spent the next couple years working on a JS app, introduced Backbone+Marionette, and became comfortable with JS. In mid-2015, I began exploring the idea of rebuilding my app's client with a modern JS stack, and decided to try these "React" and "Redux" things I was reading about. Prototyped a client rewrite, and it was clear this was the way to go.
A few months ago that rewrite finally reached feature complete, and I got to go in and rip out every last line of GWT in the codebase. I was absolutely GLEEFUL when I did that :) The React+Redux codebase, with Webpack+Babel as the build toolset, allows us to iterate so much faster and with a better dev experience.
I can understand why GWT would still have some semblance of usefulness in certain enterprise situations, but I would never touch it again myself.
I also did a lot of GWT work about a decade ago and haven't touched it since. But there's a lot of things I miss, and I would be willing to consider a "modernized" GWT if it ever materializes. I especially miss GWT-RPC; statically checked typesafe interfaces are just much faster and safer than hand-coding REST interfaces and hoping the client and server agree.
That said, I do think the train came off the rails when added all that crazy model-blah-blah-presenter pattern stuff. If GWT is ever going to make a comeback, it needs some sort of simple equivalent of Angular or React.
That said, GWT-RPC also went from being nice to a pain. The serialization formats were "proprietary", in the sense that they were GWT-specific and couldn't be reused with any other platform. There were actually two separate formats. Client->server was some kind of custom text format, while server->client was _technically_ JSON, but the contents were still basically opaque. (I found a document that tried to reverse engineer the format, and it was pretty ugly.) That was another pain point, actually - inspecting API calls in a browser's Network tab was useless, because you couldn't interpret anything out of the contents. Also, I'll take promises (and `async/await`) over GWT's ugly `MyRpcInterface/MyRpcInterfaceAsync` definitions and success/failure handlers any day.
When I rebuilt my app, I was lucky enough to be able to re-expose the same internal API endpoint implementations over JSON-RPC. That let me keep my existing backend logic, and build out the new JS client separately while keeping the old one in place until the new one was ready.
I'm surprised some sort of IDL-based client & server generator for REST services hasn't taken off.
The big problem with an IDL that people want to avoid is tight coupling, IOW, all systems have to be upgraded at once to use a change in API.
The description of Dart is also wrong. My understanding is that they are aiming at REPLACING JS in the browser, not compile to it. Compilation to JS is a stopgap to make the language useful while it's left unimplemented in Google's very own browser (A fact that never ceases to entertain me). The next web language shouldn't compile to JS, it should replace JS.
As JS becomes the asm of the web, TypeScript is going to become the C of the web. Just enough abstraction to make it possible to write, but still not enough to tank performance.
Didn't GWT-RPC solve most of this ? You could simply run them on the server, which was another nice property of Java. You could actually link nearly any java library together with any app and use it, even with isolation if necessary.
My biggest wish for TypeScript is that it was easier to use experimental flavors that supported JS features currently being considered, such as the pipeline operator proposal.
I've been using the two together recently and its been great. Like you I don't think I could ever go back to not using typescript for anything but the smallest projects.
However, often times I've found some common react patterns to be difficult to express in typescript. Namely default props and high order components. The type signatures I'v ended up with for my HoCs aren't as simple as I'd like, but I guess there is no way getting around that.
I've actually started to prefer render props over HoCs simply because the type signatures are simpler. Still no idea how to handle default props correctly.
https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in...
The React typescript definitions are still on 2.8 [1], and I imagine that they plan to stick with 2.8 until maybe the next major react release? I have no idea where people discuss things like react types for DefinitelyTyped. Github issues seem like a mess due to the sheer number of different projects sitting in a single repo.
[1] https://github.com/DefinitelyTyped/DefinitelyTyped/blob/1d96...
[1] https://github.com/DefinitelyTyped/DefinitelyTyped/blob/1d96...
Little things like this can add up to subtle bugs and tech debt if you're not careful.
That did not mean jQuery wasn't better than the ugly ad-hoc kludges in vanilla JS most web developers used at the time.
IMO, using such early proposals isn't worth the risk in production. Especially for proposals that are so young that they haven't even settled on a clear spec as to its behavior, like the pipeline operator.
It's also ironic that I couldn't write this in Typescript because I simply couldn't figure out how. These days when I use my helper, I just use any and cast the result. It sucks but until I figure out how to type proxies and use variadic generic type parameters (if and when these are supported) I don't have another solution.
Goddamn time travelers, stop messing with chronology!
Either way it wasn't Typescript itself that made it difficult. There wasn't as large of community yet, documentation was much less, editor support wasn't as great and very few packages had type definition files. Definitely typed could show all or most of their packages on GitHub at the time and many were incomplete. That was the sole way to get any type definitions.
Agreed with your comment on early proposals. Still would like to have the option to use it and double check the transformation of how it outputs. And not everything needs to be for production use. Writing for fun is an enjoyable hobby.
As I’m starting to get into the modern front end world… I do want the safety of a stronger type system but it doesn’t look like the React ecosystem has really decided which way to go.
TypeScript is popular. But flow was developed by Facebook and so it’s obviously heavily used by some of the top people.
I’ve only been reading about them, I haven’t chosen to use one yet. But I’ve been leaning on flow since it’s developed by the React team at Facebook.
That's what really frustrates me about Flow after using it for many years. We shouldn't have to rewrite valid code, write unreadable workarounds or add // $FlowFixMe annotations to avoid Flow's issues. I lead a small team of junior developers to whom I presented Flow. We now use it everywhere. But they often experience difficulties when they try to type their code. When I see what blocks them, my answer is too often "oh yeah, it's a bug in Flow. There is an issue about it on GitHub opened in 2016".
I'm right now waiting for this https://github.com/facebook/create-react-app/pull/4837 to be merged to move all my projects to TS.
Edit: and I don't blame the devs working on Flow. I guess it's more a priority issue at Facebook. Or maybe they just gave up on the community support since TS is too ahead.
The main large project you're likely to use that does not really play well with TypeScript yet is create-react-app. There's a TypeScript fork [1] which works reasonably well, but "reasonable" is not really what you'd hope.
That said, the strong community push means that they're at least considering it. [2]
[1] https://github.com/wmonk/create-react-app-typescript [2] https://github.com/facebook/create-react-app/pull/2815
Also, the CRA-TS fork runs, but the one time I played with it was when I tried to help another team set up their project, and that's when I found out it has _ridiculously_ restrictive default linting rules. Every lint error is a compile error, and it flags things like using arrow functions in render methods, which is absurd (see discussion at https://github.com/wmonk/create-react-app-typescript/issues/... ).
I have been maintaining some boilerplate to demonstrate TypeScript + React SSR that should point the reader in the right direction https://github.com/styfle/react-server-example-tsx
I'm waiting it to be merged to switch to TS.
https://github.com/Microsoft/TypeScript-React-Starter#typesc...
It does work fine, but sometimes you don't get some of the gooddies that you get in the latest js version.
Edit: oh and it’s worth noting that I’ve had much more luck finding TS definitions for third party packages than I have with Flow.
I’ve only done a cursory look. My editor (IntelliJ) supports both to some level. Webpack/Babel do too.
I’m very new to writing React and modern front end JS so it’s quite possible there are things that I should be looking out for that I don’t even know about.
I think that’s what differentiates TS from flow. Typescript thought about the whole developers workflow while flow is just a compile time typechecker.
https://github.com/flowtype/flow-language-server#supported-f...
I still have found TypeScript to be an overall more pleasant developer experience, though.
That's not to say that either TypeScript or Flow are perfect - they both are constraining with typing when it comes to composing functions last I checked.
It's not something you'd want to find in the middle of your code, yet you may have to if you want to do generic/functional programming in TS.
EDIT: one thing I miss from flow is https://github.com/gcanti/babel-plugin-tcomb - it's quite handy to spot data errors (before you have big static coverage)
But is not developed by the same developers/company as React.
I will say given what TS is competing against the fact that it so well used is rather compelling. I know all of Angular is also written in TS. It’s clearly very heavily used.
Being able to use good code completion when using other people’s components is a huge boon.
I'm really interested in this, as I'm a happy Angular user. (I'm primarily a non-frontend dev/tech/ops, but I occasionally I do frontend development.) So every time I look at a React component/codebase I'm completely lost, and I'd like to understand why and what and how.)
https://blogs.msdn.microsoft.com/typescript/2018/08/27/types...
But I am less excited about projects containing TypeScript plus the large number of transitive dependencies from a typical Babel set up; I've been greatly enjoying TypeScript instead of that.
Edit: wait it looks like they’ve changed to all Rust with C++ for the libraries. I haven’t looked at the codebase since the spring. Am I crazy that i could have sworn it was written in Go previously?
If I were looking for a regular job, I would probably filter employers based on whether they use TypeScript or not at this point (assuming it was some JavaScript-adjacent project). I'm not sure if there's really a good way of doing this sort of filtering.
I'm on the Dart team. I don't know if the author intended this, but you could read this as saying that Google isn't investing much in Dart, which isn't true.
Flutter and Fuchsia are the high profile projects that use Dart. AdWords is also built in Dart. The Dart team itself is as large as its ever been and growing. (I'd give more precise numbers, but Google generally shies away from publicly stating personnel details.) We have a ton of internal and external code written in Dart, and it's growing at a nice clip.
Different projects have different needs. If you have a large existing JS corpus that's providing a lot of value for you, then an incremental migration to TypeScript makes sense.
If you're looking to rewrite a lot of code and pay off technical debt anyway, then moving to a new language that doesn't have all of JavaScript's baggage can be a smarter choice. Dart has a cleaner object model and fewer warts like "===", etc. Making a bigger break from JS means that Dart's type system can be simpler than TypeScript's and is sound. That in turn means the compiler can rely on types for optimization and minification.
The other question is the community one: if Dart requires type bindings (like TS .d.ts files) to the large community of JS projects, how does it plan to solve the kickstart problem. It's taken TS community many years to over just the popular js libraries out there. Imho, I'd make a utility to convert/translate TS definitions into Dart wrappers... but that would require to support TS primitives almost 1:1.
None of this is meant to sound critical, I'm just genuinely curious on the process of language development.
I don't, but I agree it would be useful. We're not where I wish we were in terms of docs right now.
> if Dart requires type bindings (like TS .d.ts files) to the large community of JS projects, how does it plan to solve the kickstart problem.
We actually have a tool that will generate the proper Dart interop bindings given a TypeScript .d.ts file:
https://github.com/dart-lang/js_facade_gen
> It's taken TS community many years to over just the popular js libraries out there.
Dart is different from TypeScript in that we are deliberately a more batteries-included system. We wrote and maintain a full set of core libraries (collections, async, etc.) and Google has a well-funded team to ship and maintain a full-featured web framework (AngularDart).
So we aren't as stuck needing to rely on the JS ecosystem as TypeScript is. There is still tons of useful functionality that's available in JS and not yet Dart, which is why interop is important, but we have a lot of customers that can get by without needing much or any JS interop.
Also if you're writing something from scratch.
I see four of these statically-typed better-than-JS languages with familiar syntax that, while having their own VM (or compiler, or both), can also compile to JS:
* Dart
* Haxe
* Kotlin
* Reason
Another option would be to add TypeScript support to Closure Compiler, although it doesn't seem likely since there's no spec to guarantee compatibility.
I'd love to see Facebook, Google, and Microsoft team up in this space, instead of creating 3 separate but very highly similar tools.
Also, while we're talking about Closure, let's take a moment to appreciate its amazing UI toolkit [0]. I'd still consider many of their widgets to be the gold standard. It's written with desktop clients in mind and is incredibly feature-complete. I believe it also has pretty good accessibility, although I haven't personally tried that out. Oh, and don't forget the i18n as well! The closure library definitely has a lot of quirky aspects to it, but it's still quite amazing if you consider its age and how much stuff it supports. It's worth taking a few minutes to browse through their docs [1].
[0] https://google.github.io/closure-library/source/closure/goog...
I am really sad that TypeScript gave up on their spec. It previously was one of the strengths of the language that I was happy to cite. I guess it's a common crutch for languages (Python and so on) to say "the implementation is the spec" but without a spec to guide you, you lose sight of which features are intentional or accidents or even what the distinction between the two are.
The Closure library does has some great stuff in it. It's the accumulation of years of experience of working around lots of really subtle issues in lot of browsers. On the other side it also has a lot of code for issues that are obsolete, and it's hard to know which pieces are for what.
We used it at Lucid when we converted our codebase from Closure annotated JavaScript to TypeScript. https://www.lucidchart.com/techblog/2017/11/16/converting-60...
Google has support for using TypeScript in Closure annotated JavaScript via Clutz: https://github.com/angular/tsickle
It also has support converting TypeScript to Closure annotated JavaScript via tsickle: https://github.com/angular/clutz
Before we converted all of our codebase to TypeScript we used both Clutz and tsickle. It was complicated to setup, but it worked. Now we just use tsickle. It's great to get the optimization of the Closure Compiler while using TypeScript.
I agree, it would be cool for someone to do the same thing for Typescript, I seem to remember a repo a while back on Github that said someone was experimenting with it - cant for the life of me remember where though!
It'll probably happen anyway, but the current competition will determine which tool that will be. So far TS looks like it's winning it, but, clearly, not by a large enough margin that the industry coalesces around it - yet.
ES6 (or whatever we’re supposed to refer to it as now) is good enough for many things, but when you see it used heavily with, for example, proptype hints... you get the feeling that there really is a trend these days towards flavoring static type checking and the error checking that offers.
I think its an interesting shift, with python and javascript both being poster child dynamic languages, but people who use them seriously going... ‘yeah, type checking is actually pretty handy...’.
Sadly, standards seem to be sitting on their thumbs with weak excuses - people doing it different ways therefore we do nothing. Just take the larger market share compiler, add a few handy features from others and call it a day.
https://ecmascript-daily.github.io/pages/status-of-static-ty...
That said, yes, you can compile TS to JS with no ecmascript compatibility constructs to just remove types and essentially "eject" TS into JS.
Edit - changed previous sentence to "proptype hint". I originally erroneously read the parent as saying "prototype hint" which I couldn't find results for, but even after correcting my reading error my question still stands.
PropTypes are used for a combination of debugging during development ("you accidentally passed a string instead of a number", or "you forgot to include a required prop"), as well as documentation for a component. React devs have traditionally used PropTypes to act as readable documentation of a component's expected props, and there are tools that can extract PropTypes usages and generate documentation files.
However, with the rise of TS and Flow as static type systems, the need for a runtime-based type checker has gone down, especially since people using TS/Flow have probably already declared types for a given component's props.
Ie. ‘lite’ type checking, used in react.
(did you perhaps see the results for ‘javascript prop type hint’ as a google autocorrect suggestion or something? This is a well known term, but I’m pretty amazed two seconds of google didn’t discover what it was...)
Flow has been great, but I've just tried to update to the latest version and I'm dealing with a flood of indecipherable errors, especially from the react-dnd library. Looks like no-one is really maintaining the flow types so I'm on my own, and I don't even know where to start.
I also haven't been able to track down some errors, like "Cannot read property 'foo' of undefined". Flow thinks that this variable can never be undefined, and I have no idea how it's happening. It might even be a bug in Immutable.js, but I have no idea.
So if TypeScript is more popular and has a bigger community, then maybe it's worth migrating just so I can get more help with these issues. And maybe TypeScript will catch more cases as well.
The reason I initially chose Flow was the fact that their goals were more ambitious (trying to build a sound type system for example). And there were features that Flow had and TypeScript didn't (tagged unions for example).
The reason I ultimately switched to TypeScript was that after a couple of years, it had simply caught up and surpassed in the one area it was behind Flow (i.e. expressiveness of the type system and type-level programming), and that it had widened the lead in the areas that it was always better at, like much better tooling, bigger community, core team being more engaged with the community, releasing RCs to smooth out the rough edges, etc.
So yes, I switched to TypeScript, and I see that I'm spending less time working around the type system's quirks and more time getting things done. I'm also very much enjoying the fact that I can express types in TS that I never could in Flow. So my codebase has much better type coverage in TypeScript than it did with Flow.
[0] https://www.typescriptlang.org/docs/handbook/advanced-types....
If you have the time, would you mind commenting specifically on this?
I'm using Flow, rather than TS, for a bunch of reasons you are probably familiar with, but over time I'm just wondering more and more if switching to TS might be worth it just for the tooling.
With Flow in VS Code (via the flow-for-vscode plugin), whilst things have slowly and steadily improved over the last 2 years it is still quite a way from 'just works'. I get the impression that the story for TS with VS Code is a lot different, and everything would just work out the box (intellisense, auto import, meaningful error messages tied to line numbers, etc) though I simply haven't yet found the justification to invest the time in migrating just to check this. If I'm wrong and it's the same or only very slightly better, it would obviously have been a time sink for not really much benefit.
Do you have any insights or advice on this? Even if you're not a VS Code user, what tools do you use that are better with TS than Flow?
The way I finally did it was that I tried out TS on a side-project that I wrote from scratch. I did expect better tooling with TS, but I was still surprised by how better the experience was.
Auto import just worked. Same with code navigation. And they made me work much faster. Intellisense was also much better. And the error messages more readable. (And they've gotten even better since)
All of these things work to some extent in flow+vscode, but the experience with TS was incomparably better.
I was still hesitant to switch the larger project to TS though, mainly because we were using some of Flow's more advanced features to type-check a function like `wrap()` in this code:
const obj = {foo: true, bar: {baz: 2}}
const wrappedObj = wrap(obj)
wrappedObj.get('foo') // returns true
wrappedObj.get('bar').set('baz', 'some string') // type error. baz must be a number
This was almost possible to do in Flow using `$ElementType<>` and `$Call<>`, but TS had no counterpart for `$Call<>`. Luckily though, TS soon came up with conditional types, which turned out to be a much more reliable way to handle these cases.That's when I decided to switch the codebase to TS. It took about 5 days. It wasn't straightforward, but in the end, it gave us a much smoother developer experience.
https://blogs.msdn.microsoft.com/typescript/2018/05/31/annou...
TypeScript has a nice architecture that provides a language service that can be used by any editor, but my impression is that VS Code is the "flagship" editor that gets these features first.
I personally use WebStorm, and I find its TypeScript support much better than its Flow support in various ways (though I haven't tried Flow in a while). Imports get added automatically, autocomplete is fast and has better results, navigation just works, etc. Part of this is historical: WebStorm supported TypeScript first, and was hesitant to support Flow during the long period of time when Flow didn't work on Windows. It now has Flow support, but I think it's just not as polished, and I don't see it come up as much in the release notes.
TypeScript is based on an AST; which means it's inferences are limited. For example it requires you to type the parameters to a function. If the return type is derived from untyped parameters then TypeScript falls back to typing the return type as 'any'.
Flow maps the flow (hence the name) of types throughout an application, which means that it can derive the signature of a function based on the types that are passed into it. That should mean that it's a little easier to add to an existing project.
Here's an example of Flow finding an error without any type annotations: https://flow.org/try/#0PTAEAEDMBsHsHcBQBjWA7AzgF1AQwCb4BMoAv...
And TypeScript missing the same error: http://www.typescriptlang.org/play/#src=const%20add2%20%3D%2....
TypeScript can do type refinements based on the flow (e.g. a null check refines a type with null to one without) but can't do what you just showed. Are there any tools that can emit the inferred types to source code? I just now got a vision of using flow style type inference to gradually augment a project with either flow or TS types with very little work.
Ironically, we’re considering switching to TypeScript and in my team the lack of inference is seen as an advantage. It forces people to consider their types as part of the design of their interfaces.
I quit using it a few years back because it was a _nightmare_ having to write d.ts files for everything or be unable to use noImplictAny for your own files. `AllowJs` wasn't even a thing when I started using it, but even after its addition, this problem continued to be absolutely disastrous for my project. I remember being very disillusioned with it because all of their materials (website, docs) kept hammering on how effortless and incremental it was to use with JavaScript, yet `AllowJS` wasn't even a thing for the longest time...
I also had very severe issues with its importing of npm modules, even ones that supported TypeScript. Sometimes it would double-parse bundled d.ts files resulting in a huge error output. Other times it would just completely fail to resolve import paths no matter what I tried.
I remember various workarounds like having to define empty modules for each plain-JS import, or using `///` imports for certain files, and it was a nightmare (and I found many similar issues on StackOverflow that were unsolved). The maintainers at the time considered these terrible workarounds as valid solutions, and thus would almost not even entertain reports regarding these problems.
Bottom line: I never write my own definitions for other projects.
In our project I’ve found we make a lot less mistakes than with pure JS and there’s a lot less pointless type check unit tests due to the guarantee’s it gives us. io-ts (https://github.com/gcanti/io-ts) around rest endpoints checking json input as well has been a godsend.
> "compilerOptions": { "strict": true }
But given the huge number of other options I worry that like GCC's '-Wall', that doesn't actually give you the strongest possible type checking. Anyone know about that? My aim with Typescript is to turn JS into OCaml.
If that's the goal, why not use the real thing http://ocsigen.org/js_of_ocaml/ ?
Types just smuggle themselves in with the rest of the program (granted they only cover a subset of the bugs tests do).
The alternatives to TypeScript seem increasingly compelling to me.
It was good to see Haxe mentioned even in passing; I really enjoy using it and — as others have noted[1] — it feels like a “better” TypeScript.
Haxe has great features both at the language-level (pattern matching, algebraic data types, array comprehensions, and more[2]) and tooling-level (cross-compilation to JavaScript, native code and dynamic languages, a fast compilation server[3], good VS Code support in Haxe 4, and a bunch of cross-platform game frameworks[4]). I wish more people would try it! https://haxe.org/
Reason is also compelling; it will be better still once Bucklescript's Belt library is out of beta and some warts in Reason/OCaml are smoothed out — lack of ad-hoc polymorphism[5] and lack of unicode support without BuckleScript string literals being two examples.
[1]: https://news.ycombinator.com/item?id=10009290
[2]: https://haxe.org/documentation/introduction/language-feature...
[3]: https://haxe.org/blog/nicolas-about-haxe-episode-1/
https://news.ycombinator.com/item?id=17896925
I used to tinker a lot with OCaml around 13 years(!) ago. It's neat to see people are still working on fixing some of its problems. It would be fun to find a reason to use it again.
Of course I am just joking. Well, the author faced the same dilemma that we all face when instead of joining the next-to-be-unicorn startup we join an established company which has been operating for more than one decade. Namely legacy code.
They should pick up a copy of 'Working effectively with legacy code'. They might extrapolate some of those advices and apply to their situation.
It seems like something that only exists due to the popularity of Angular, where I can only assume the experience is significantly better than with React.
The type system is frankly disappointing, and the errors the compiler spits out at you (besides the most obvious ones) are almost always useless or gibberish and at times even more harmful than helpful.
It's better than nothing I guess, but I can't help but feel extremely underwhelmed with it given how many people use it. Are all of the people in this thread Angular developers or something?
Many people are doing TS wrong. They add types everywhere. Honestly, you should write as many types as necessary, but not more. Use type inference which works remarkably well.
It helps to create a type reference for your database schema, so you don't try to insert something weird or insert with missing columns.
I'd love to see examples of such errors. (And, ideally, accompanying code example)
I was receiving an error complaining about a missing prop on a component I was wrapping with `injectIntl` from `react-intl` and could not for the life of me figure out what was wrong. Searching the type error wasn't helpful, and it wasn't until I really dug down and spent about a half hour of my time that I realized it was because we had something like `injectIntl(connect(foo, bar)(SomeComponent))` instead of `connect(foo, bar)(injectIntl(SomeComponent))`
The type error did not in any way make that clear or obvious. If I had to compare it to anything, it would probably be the type of error messages you see if you play around with type level programming/dependent types in Haskell. Or the types of error messages you see when writing Clojure.
We have started using Angular 2 (now.. 6?) with TypeScript for a project last year and I never had big issues with TypeScript.
Last month, one of our teams started a React project and given the success of using TypeScript before, they opted to do the same with their project. I've walked them through a few things but found myself getting frustrated a lot with weird TypeScript errors. Especially things like typing your Props was such a nightmare that we resorted to "any" a lot more than I'd like.
The project is not using TypeScript 3 so I am unsure whether that would get rid of some problems but React + TypeScript was just a frustrating experience for us.
I think the most immediate and obvious pain point for me is typing HOCs. It's basically a matter of rearranging how you apply them until TS can automatically infer a type for you. At the same time, using `compose` instead of applying them individually solves that problem but results in strange types (that are different from the type TS infers if you apply the HOCs manually yourself in an order that makes it happy) that I suspect will cause type errors down the road when we convert the files that make use of it to TS as well.
FWIW I use Typescript with React, have had very few bad experiences(but not zero) and I'm never going back.
As far as going back goes - it's preferable to plain JS I guess? But that's not saying all that much. I don't know - I'm sure I'll appreciate it more after this migration period is finished and things start to stabilize, but as of right now I'm definitely not enjoying it.
I like this :)
What I would like to have in TS is a more expressive type system - the current is somewhat basic(e.g. you can't have a Symbol as a dictionary key - interesting given that it's possible in JS. Also you can't mix dictionary fields with regular ones in one class/interface).
EDIT: typo.
I think what we need is a subset of JavaScript, not a superset. There are things we should not be able to do in JavaScript in a web browser because to me that's where JavaScript belongs. I think the whole idea of js on the server or in other kind of projects is very silly. But that's besides the point.
But I agree with your example of symbol in dict. I would be surprised if it isn't already on the roadmap. Have you tried reaching out to the typescript people?
It's not just on the roadmap, it's in code review/iteration as of last week: https://github.com/Microsoft/TypeScript/pull/26797
And the version shipped on NPM [1] has options for either native, Java, or JS.
Edit: here you go: https://www.npmjs.com/package/google-closure-compiler
If you go all the way and make it sound with variance annotations, banning asserts & under specified types, etc. then you end up with a language that sucks to use in practice.
If you go to the other extreme, you don’t have static types at all.
If different parts of your code are typed to varying degrees, or you use a lot of unsound types/inferences, maybe there’s a way to assign a confidence score to every type to indicate how accurate you think it is. Maybe there’s a clever way to statically compute that score, or you can instrument some % of prod traffic at runtime to observe types with lower confidence (Node has this, or see MonkeyType or Reticulated Python). Then take that info and feed it into Closure compiler.
Variance annotations aren't quite what would make the language (in strict mode) sound. Specifically, what makes it unsound is the `any` type (generally) and the lack of enforced variance on methods, non-function properties, and index signatures. It doesn't need annotations to determine variance - type parameter variance can be inferred from where in a type a type parameter is used. It already does so for functions (that's the strict flag's strictFunctionTypes subflag). The real issue is that far, far too many people rely on, eg, unsound array assignments (array aughta be invariant over what it contains but it's often treated covariantly), for it to be reasonable to be a default. However it could always be changed (or added) in the future - that's what the strictness flags are for, ideally; providing ways to ratchet up the safety such that it won't permanently break longtime users of the language.
However, it's kind of against the spirit of TypeScript to insert runtime checks. For example because the type system models 'undefined', to model out of bounds array accesses you'd either need to make every array access have type T|undefined or insert bounds checks that throw. (I believe Dart does the latter.)
Generics are a complex concept for people to grasp without some time playing and reading docs, but once you learn it, you can express almost everything you want.
But for simple projects you can get away with all but the most basic of generics, if any at all.
With the release of conditional types, I find most of my js typing cases are covered.
Though tbh I've always leant toward the side of "if you can't express it easily, then you're being to JavaScripty".
Another issue is that handling of string literals as types can be wonky when they're being compared against the type "string", which they should always satisfy but sometimes don't.
What does this mean in practice? I know about variable hoisting and function scoping, but not about old JS GC algos.
Having the programmer define a variable before the loop and then reuse it each iteration meant that all that allocation and garbage collection wasn’t necessary during the passes of the loop.
Transpiled Typescript code I expect, so?
"Because TypeScript already mostly works — that's part of the reason to adopt it"... c'mon
Typesafety is a small part of it and I’m not sure whether switching or choosing entire dev tooling based on just that is worth it. Just structure your code better and use react prop types and most of type issues go away, in react code bases.
We primarily do JavaScript, and I see no issues with it when you set up governance in how to use it.
I don’t think building your own libraries is really a bad thing either, in fact I think you should do so often instead of relying on 3rd party packages of quality you typically judge on how many times they’ve been downloaded if you’re being honest.
I think typescript is silly. It works with legacy code, sure, but if you’re refactoring you might as well rewrite your JS or if you’re compiling to JS you might as well chose Dart which is vastly superior to typescript.
I don’t really see type safety as an issue. I can’t remember when it was a problem for us, and we operate millions of lines of code, but they are all written with governance. Want a number? Then call your argument numWhatever and check your input. It’s really as easy as that.
I mean, sure type checks will prevent shitty code from compiling, but really, just don’t write shitty code. I know that sounds silly to some people, but 95% of what you write is about shifting data around through simple mechanics, it really shouldn’t be so hard to do it right.
You won’t see an engineer go “oops that support beam in your building wasn’t right, my bad” and programmers really shouldn’t get that luxury either. If they write shitty code then figure out why, maybe they need more time, maybe they need training, maybe they need governance or maybe they need to be replaced.
But hey, feel free to fix your shitty code with code that’s only less shitty because your compiler protects you. Just know that typescript comes with a different set of risks, once you need your JS codebase to move forward in a way that isn’t supported by JS.
I mean... Yes? That's exactly what it's for. That's all it's for. That's all I want out of it, and that's what it does. I'm not really sure what you're railing against here.
Especially not if you’re not converting your entire project to typescript, and if you’re converting the entirety of it, then why not use a better language?
I think typescript is popular because it’s very java/c# like and I think it’s dangerous because it allows you to write bits of your program with the safety it provides and other bits without it.
So you’ll have programmers thinking they are safe, when they are really not.
Also, it doesn't fix shitty code. It just lets the compiler warn you when you're either making a mistake or misunderstanding some other part of your code base.
You should really try it before you say it doesn't help.
I think at beginning it was mostly used by developers familiar with Microsoft stack (.NET world mostly). But TS was not designed for C# developers, it was designed for JS ones! And I'm super happy it's becoming more and more popular in more "mainstream" frontend community.
I'll just copy my old response to some very old thread that talk about why it not just "a language for C# developers":
" Once sometimes asked me "Isn't Typescript a language for C# developers that don't know JavaScript" It's unfortunate that people think that TS is similar to C# just because it came from Microsoft. Flow language is like 80% similar to TS, but no one says it's similar to C#.
TS is just JS + new features from future JS specification + optional type system. And optional type system is fundamentally different than the one in C#, and it was designed to fit well with JS patterns and idioms (structural vs nominal type system)
If you look at TS code that looks like C#, it's because JS looks like that (classes syntax, classical inheritance, lambda syntax - it's all ES7 (or ES2016/ES2017, or whatever it's called now) "
Dart is very poorly designed, and they managed that even without the constraint of being 100% compatible with good old broken javascript.
It doesn't have null safety. This right here, is enough said and yet we could continue for hours, like how its standard library made the same 20 years old mistakes as java with things like "immutable collections are just mutable collections that throw exceptions", etc, etc.
Flutter might increase the demand and pressure on Dart quality but it's not a good language by any stretch of the imagination.
Speaking of uninformed...Dart is significantly faster for one. It's also not encumbered by being a superset to one of the worst scripting languages ever designed and, thus, does not have to deal with all of the baggage JavaScript brings with it.
>Dart is very poorly designed.
Amusing when you consider the clusterfuck that is JavaScript.
Why do you use a screen to look at your code? Sure it helps you see what you are typing but I mean just don't type wrong to begin with and you don't need a screen to see what you just types! Just focus! Don't write that shitty code so you need a screen to keep it from being shitty.
I'm not trying to be snarky I'm trying to make the point that every single tool we use from a compiler, a type system, unit tests, a monitor... are tools we didn't have from the beginning as programmers. And every time a new tool came, there were always people saying "you don't need those crutches, just do it right instead" (Writing machine code, using punch cards etc). Also, they were always wrong.
It sounds like you have reinvented the Hungarian notation - 15 years after it was phased out?
Many of such overcomicated systems come from trying to use the latest coolest thing without thinking about if it improved anything. the tools were never used correctly and the person just moved on, marking JS as a shitty language with a shitty ecosystem.
When there’s always something new on the horizon it’s too easy to assume the previous difficulty was because of the old tool vs taking the time to just learn the tool.
There are many developers who don’t really understand MVC for example and so much pain comes from trying to ham fist a jquery mentality into one.
I think it’s inferior because it allows you to rewrite only parts, and unless you convert your entire code base, then you’ll not have type safety. Because the bits that aren’t typescript won’t warn you when you compile.
You just wrote exactly why static types are great: you get warnings when you forget to refactor your shitty (sic) JS code.
We write all our new code in good ol ES6 flavor of JavaScript and typehint in jsdoc. Typescript as a typechecker serves as very well.
It’s a great incremental adoption strategy.
This seems a great first step.
{
“compilerOptions”: {
“allowJs”: true,
“esModuleInterop”: true
},
“include”: [ “src/**/*” ],
“exclude”: [ “node_modules/**/*” ]
}
You’ll probably have to tweak that, but I hope it helps.https://www.typescriptlang.org/docs/handbook/compiler-option...
Also Google’s puppeteer project is typechecked with tsc and the type info is all in jsdocs
That's exactly why it's superior, your project just becomes better step by step without an expensive and complicated full rewrite.
I think the problem is that people are abusing JavaScript for large projects when JavaScript's purpose is small-scale DOM manipulation in response to UI events.
Oh no, please not the ugly Microsoft naming syntax again... I thought that died a long time ago.