DEV Community

Ben Halpern
Ben Halpern

Posted on

Thoughts on migrating to TypeScript and improving the overall quality of the frontend DEV codebase

I think the evolution and increased popularity of TypeScript over the past year or so means that it is a good time to migrate towards using it on DEV.

Nick Taylor has been the biggest proponent, but it all jives with my view of things.

Read more here:

I did not want us to be too far on the bleeding edge of frontend technology and that continues to be my stance, but I think TypeScript is in a good place and Rails' support of "modern" JavaScript is likewise in a good place.

As it currently stands, we have some of our JavaScript in the "old" app/assets/javascripts area of the codebase and some in the new app/javascript area which is configured via Webpacker.

As mentioned by others, I don't think we need to wholely re-write in TypeScript, but we should begin refactoring and writing new features this way. And in general, we should definitely be migrating the oldest JavaScript into the new area to whatever extent possible.

I think this initiative can pretty effectively be led by the community rather than top down from our team, because we won't need to provide a lot of specific instruction in order to make improvements in these areas.

Any pull requests to provide good instructions for this approach in the README and/or docs would be appreciated to get the ball rolling on this.

Part of the reason I feel like we can get moving on some of this now is that GitPod might be useful for helping frontend developers get up and running with the codebase and making changes without the worry of installing and getting the app running locally.

Only time will tell if GitPod leads to true productivity enhancements for frontend developers looking to contribute, but I think it's something worth exploring.

Oldest comments (21)

Collapse
 
theodesp profile image
Theofanis Despoudis

I think it's a solid move. It will also make your devs less bored if you give them new tools to play.

Collapse
 
john_papa profile image
John Papa

I find one of the easiest and most comfortable ways to slide into TypeScript are to leave the current code base as-is and first add // @ts-check to the top of your JavaScript files inside of VS Code. This helps the editor treat your javascript with the typescript compiler. It will raise issues you may not known you had. This will not change the way your app runs, so it is a very low risk (no risk) way to start.

Second ... once comfortable ... I recommend adding new files as TypeScript. You'd likely want to create a tsconfig.json file and a tsc npm script to compile the typescript. But the code itself ... I like to start with the same coding styles I use in JavaScript. In other words, if you are using functions and constants and let/var ... continue doing so. Just add a little bit of typing and interfaces as you go.

What's the biggest hangup in typescript I see? One of the big ones I try to help folks with is avoiding the feeling that everything must be typed. any is ok. Embrace it when you start out. You can always get more specific later if it helps. Also, if the type can be implicitly determined, then don't explicitly type it. Here is an example ...

let name1: string  = 'john papa';

let name2 = 'john papa';

Notice that the second one is still a string. We defined it as such. Why bother adding more code? More code is more to maintain and it can make code harder to read. Not buying it yet ... try this one ...

getSpeakers(): Observable<Speaker[]> {
    let speakers$: Observable<Speaker[]>;
    speakers$ = <Observable<Speaker[]>>this.http.get<Speaker[]>(speakersUrl);
    return speakers$;
  }

This could be much more readable like this ...

getSpeakers(): Observable<Speaker[]> {
    const speakers$ = this.http.get<Speaker[]>(speakersUrl);
    return speakers$;
  }

Thanks for indulging my stray thoughts :)

Collapse
 
rhymes profile image
rhymes

Love this approach!

Collapse
 
ssalka profile image
Steven Salka

If you use tslint, you can enforce this with the no-inferrable-types rule 🙂

Collapse
 
jacobmgevans profile image
Jacob Evans

This!

Collapse
 
karataev profile image
Eugene Karataev

I have no experience with TypeScript, so I might say something stupid here. But what's the point of continious integration of TypeScript in a big project? It's very unlikely that you'll rewrite all your codebase to TypeScript, so part of your code will be typed and other part will be just vanilla javascript. I guess you will not feel secure backed by types, because you'll know that it's not true.

In total you'll get:

  • New dependency, configuration, transpiling step, .d.ts files
  • More code to type +- New code will be covered with types, but connections with old code will not
Collapse
 
johnbwoodruff profile image
John Woodruff

I work on a large older codebase that we decided to convert to TypeScript. While it has taken us some time to get there, we are at probably 95% TypeScript, and the rest should be taken care of within a month. It is definitely possible, and is easier to do the more you realize it helps you with code quality and developer happiness. It went from being a chore to being an exciting thing to convert a file over here and there.

Collapse
 
john_papa profile image
John Papa • Edited

Thanks for replying! These are good questions to ask. They are not "stupid" in my opinion :)

You do write more code with TS, but you also get a stronger sense of finding issues while coding vs finding them while they code is in production. To me, one of the biggest values in TS is that many potential bugs surface themselves at dev time vs run time.

Is there value in only having new code in TS? There can be as this new code would make me feel more confident. You can also add the // @ts-check to existing JavaScript in VS Code ... give that a shot. That alone is quite amazing at what it can surface in existing JavaScript.

New thought --- Another option is to run the typescript compiler on javascript. No TypeScript at all. The compiler will examine the javascript and report any issues it finds (it's like adding ts-check to all of your files). I did this on a large codebase and it did indeed surface a lot of potential issues that were hiding. This is a super low (no) risk way of trying it.

Again, thanks for the great questions. Always good to ask - especially if something isn't quite feeling right.

Thread Thread
 
karataev profile image
Eugene Karataev

Oh, I didn't know that I can run typescript compiler on javascript code without modifying the existing code. Thanks, I'll give it a try.

Thread Thread
 
john_papa profile image
John Papa

Set allowJs to true in the tsconfig.json file to tell typescript to look at the js.

Good luck!

Thread Thread
 
amcsi profile image
Attila Szeremi⚡

Why didn't you just recommend this from the start? Seems a lot simpler than to add // @ts-check to every single JS file like you said in your original comment :P

Collapse
 
nickytonline profile image
Nick Taylor

I've just freed up from some other TypeScript OSS, so I'm going to start jamming on this to provide a POC.

For those interested, this is what has been taking most of my OSS bandwidth.

Enable strict-mode for TypeScript #1783

Basically going with the non-null assertion operator in almost all places, because as mentioned in github.com/sindresorhus/refined-gi..., the assumption with the extension is that the DOM nodes referenced in most cases are expected to be there. If they aren't, the extension breaks, a bug is filed and it's fixed.

One thing to note @bfred-it, is currently dom-chef types need to handle JSX (Element and IntrinsicElements) or we import @types/react.

Collapse
 
kayis profile image
K

ReasonML plzkthxbye 🙃

Collapse
 
ben profile image
Ben Halpern

Does ReasonML compile to directly to JavaScript without library overhead in prod?

I'd be open to multiple approaches in different areas if it doesn't add up to more and more bytes needing to be shipped.

Collapse
 
yawaramin profile image
Yawar Amin

ReasonML compiles to pretty minimal strict ES5 that can at times look hand-written. There is very little library overhead and if you know how, you can cut it out almost entirely. See reasonml.chat/t/writing-javascript... for more details. I'm actually working on a very simple ReasonML library right now that will have no library overhead and can be used trivially by JavaScript callers. The transpiler was designed that way, to enable incremental migration.

This is also a good time to try it out–there's been a new ReasonReact release that supports writing zero-overhead React components, with hooks support: reasonml.github.io/reason-react/bl...

On top of all that, ReasonML output minifies really well with Rollup (dead code elimination).

Collapse
 
kamilchm profile image
Kamil Chmielewski

It depends how you write it. See reasonml.chat/t/writing-javascript...

Collapse
 
restoreddev profile image
Andrew Davis

I would like to hear about the experience if you do refactor to TS. It seems like a big departure for a Ruby app. Every time I’ve tried to use it before, it feels very foreign to JavaScript and it’s dynamic nature.

Collapse
 
matthewbdaly profile image
Matthew Daly

To my mind, Flow has always made more sense than Typescript.

Other languages that compile to Javascript have historically not done all that well in the long term (not many people use Coffeescript or Dart any more), and the refrain that you should always bet on Javascript is pretty reasonable.

It therefore feels safer to adopt Flow, which is just annotations for Javascript, than Typescript. The toolchain is generally easier to set up, and it can be fairly easily added to legacy projects. Also, I tend to use React for my front end stuff these days, which has historically had a stronger emphasis on Flow than Typescript.

Collapse
 
omrisama profile image
Omri Gabay

As someone who works on a Rails codebase, it's really nice to see other Rails applications in the wild and I appreciate DEV.to for it.

Collapse
 
andrewbrown profile image
Andrew Brown 🇨🇦

Any change you want to make Ben I'll support.

Collapse
 
vekzdran profile image
Vedran Mandić

I know it is a silly comment, but really when you try it out you’ll be asking yourself “why did I even question this?”. You can go with the ts-check flag then advance to the most non-restrictive tsconfig and write javascript in .ts files, and then advance with the typings, interfaces, generics etc. It is worth to read the tsconfig options in the docs and a maybe lighter approach to feature by feature is to read Marius Schulz’s blog. You will not regret, this will be a fantastic, useful and fun upgrade!