1. 4

    In the Slack era this is crucial for all kinds of work, not just remote. This post sums up the question, IMO. It should be asked during interviews.

    1. 1

      Do you people use both eslint and tslint or only the latter?

      1. 2

        My understanding is that tslint is being deprecated in favour of ESLint this year. So I guess unless it’s really valuable we’ll probably not adopt it if we switch to TS.

        Would be interesting to hear what others are doing?

        1. 2

          Wrote a blog post about exploring the move from from tslint to eslint: https://artsy.github.io/blog/2019/01/29/from-tslint-to-eslint if yr interested.

          We haven’t made the full switch yet but it seems promising.

      1. 12

        This has been nothing but a net win for our team, and we have a similar setup as you, with CoffeeScript + Backbone + React -> And now TypeScript. Adding TS support was also painless thanks to @babel/preset-typescript. Then TSC is only used as a type-checker.

        If you want a peak at our codebase, see: https://github.com/artsy/force. (These days it’s mostly used as a shell for components / apps imported from https://github.com/artsy/reaction, though. Reaction is 100% TypeScript.)

        As far as typings go – this is important – unless you have someone holding folks’ hands and helping them through, i wouldn’t turn on strict TS settings. When things aren’t strict it’s basically just JS and then everything is additive. As your team learns more and becomes more familiar with TS, more types will be added and things will get stricter on their own, organically. For entirely new codebases, it’s very worth it to start with strict settings. For old code-bases, migrations, or teams who need to onboard, not worth it.

        Don’t be afraid of any if you can’t figure something out! Use any to keep the flow of things going smoothly, with // FIXME: any attached. Momentum is important. Keep the momentum! Then later, go back and fix the any’s. If you can’t figure it out now, that’s ok too – your codebase is already safer just being in the type-checking pipeline in many other ways.

        For typing react children, there’s React.ReactNode, JSX.Element, React.FC and so on. It can get as strict or as loose as you’d like it to get, but typically ReactNode and JSX.Element will cover things.

        Go slowly, you’ll learn more with time. At Artsy we had a few (two) people who were familiar with TS, and the rest not. We’d never go back to untyped code now, even though in the beginning it was a little confusing at times. Absolutely, without a doubt, it was worth it.

        1. 2

          Thanks! How did you deal with the CoffeeScript, if at all? I assume the Typescript compiler doesn’t know what to do with it?

          I think my team is pretty over the CoffeeScript, anyway - I think they’d all rather be writing ES6. I thought maybe we should compile the Coffee to JS and commit it, then delete the Coffee, just as a way to get to an all-JS codebase that Typescript can understand.

          1. 3

            How did you deal with the CoffeeScript, if at all

            Everything is piped through webpack and babel, and things all exist side-by-side: https://github.com/artsy/force/blob/master/webpack/envs/baseConfig.js#L21-L23 https://github.com/artsy/force/blob/master/webpack/envs/baseConfig.js#L38-L49 https://github.com/artsy/force/blob/master/.babelrc#L13

            For files we find we touch a lot, like lower level lib code, we’ve converted that from Coffee to TS, but 99% of the CS we’ve written is still CS, and we tend to not touch it – its just maintenance code at this point.

            As mentioned below, rather than getting bogged down worrying about your large code base, it’s best to setup TypeScript and then use it to write new code, and then – if need be – convert older, more critical parts later via something like https://decaffeinate-project.org/.

            1. 1

              Thanks, I’ll look into that. Out of curiosity, have you ever thought about just committing the compiled Coffee, so that you don’t need to support it anymore? I have increasing numbers of engineers who don’t know Coffeescript (even though it’s just a different syntax) and don’t want to learn it, but we do unfortunately have quite a lot of coffee that still needs updating. If I’m going to ask them to learn one thing it’ll be TS, not Coffee, which is why I’ve wondered about just getting rid of it…

              1. 2

                No, we have the assumption that if need be people will have to work with it, which is a bit annoying but also not the worst thing. It’s still a pretty nice lang all said, just not type-checked :)

                1. 1

                  Yeah, I mean… it’s not that hard IMO to learn CoffeeScript. I don’t personally think it’s a big ask for people on my team to deal with it occasionally.

          2. 1

            I just want to say that I love Artsy and your guys’ work.

            1. 2

              Thank you!

          1. 4

            Finally, a lobste.rs conversation I can meaningfully contribute to! I spent a lot of time converting CoffeeScript to TypeScript on my employer’s codebase — something like 600 .coffee classes at peak :)

            As @sibeliuss mentioned elsewhere, decaffeinate is pretty great for getting rid of the CoffeeScript. We’re actively using it to get rid of our remaining CoffeeScript, with a few extra steps after to add rough TypeScript typings. If you’re not ready to make that jump (or there aren’t any tests to validate that nothing has regressed from the decaffeination process), there are still options!

            When I started our migration (back when TypeScript 2.1 was new), I really wanted to use --no-implicit-any, since that’s where many of our bugs came from at the time. We took a two-pronged approach:

            1. For slow-moving, core modules (network queues, logging facades, etc.), hand-write .d.ts files. You’ll get huge benefits in your typescript without having to worry about regressions.
            2. For modules that change often, I wrote a tool that converts the CoffeeScript compiler’s AST to a TypeScript .d.ts file. Function names and argument names come over correctly, but all paramters are optional and any (but explicit any, so new TypeScript gets strict typing from the start!). Module exports do get exposed properly though, and it’s been running pretty smoothly for us for about two years.

            We’re doing more conversion (mentioned above) to finally get rid of the old stuff. Now that --checkJs is a possibility in TypeScript, decaffeinate definitely seems worth your time!


            That tool is available on Github if you think it’d help at all. A few of our conventions got encoded into the translation (mostly around method visibility), but it’s otherwise a straightforward translation. There will eventually be a corporate blog post about that whenever I get around to editing it :)

            1. 1

              Ohh, splitshot is interesting, thanks!

              1. 1

                Wow, splitshot seems really cool! I will definitely take a look at that. I bet it was an interesting project to work on. I would love to see the blog post about it when it’s ready - you should post it to Lobsters :)

                (and also if you would PM it to me or put it in a reply to this message so I don’t miss it, that’d be really helpful)

              1. 8

                One thing you can do immediately without changing any code is add a tsconfig file to the project and tell it to check the JS files too, then pull in all the @types/ libraries into the devDependencies.

                Then you can start including small parts of the project in your tsconfig, because if you feed it the whole thing at once it will most likely find a TON of errors and false positives, which is counterproductive and discouraging.

                After you fix the low-hanging fruit you’ll likely be left with a bunch of false positives which you would only be able to fix by adding type annotations. Now, you could just rename File.js -> File.ts, and if you can get away with it easily, i.e. if you’re using Babel >=v7 which has native support for TS, by all means do it, but maybe you can’t and integrating TS into the build process will take more time than you/your team is willing to spend on this experiment and will otherwise just discourage you from trying.

                What you can do in this case is sneak in type annotations right in the JS files inside JSDoc comments, and when things get too hairy add a .d.ts file (which doesn’t have to be required to use the types defined in it, unlike .ts files). Typescript can read those comments just as if they were annotations in TS files. You can get far with this approach, and when you’ll eventually make the switch to TS you’ll just have to transcribe the JSDoc annotations to proper TS syntax. Or you can just keep using the JSDoc-annotated JS files if you think that’s too big an effort.

                Edit: this page has lots of documentation on JSDoc annotations.

                1. 4

                  We’ve found that using checkJs: true can be hugely discouraging in a large codebase migration. Best (IMO) to keep a clear division between old and new.

                  1. 4

                    Yes, that’s why I mentioned including just a small part, by using files or include in the tsconfig file. That should keep it more manageable.

                    1. 1

                      Thanks for the ideas! It sounds like maybe before we start it would be helpful to have an upgraded build pipeline? Latest babel, etc…

                      1. 2

                        That would definitely help a lot, @babel/preset-typescript makes it trivial to use TS. But you might have trouble with this (I recently had to upgrade webpack and babel on a Backbone + TS/React codebase and it caused a lot of pain) while adding a tsconfig and JSDoc annotations is a low effort and low commitment process that you can start doing right away to see some benefits.