Migrating a Nodejs Telegram Bot to TypeScript - Part 2

Hello everyone! In today's short post, I'm going to tell you about some of the insights I gained while finishing the migration of my bot to TypeScript. This post is the second part of this post, so you might want to check out that one too.

Migrating all files from JavaScript to TypeScript

Moving all files to TypeScript is relatively straightforward. Especially, since I was using ES6 and JavaScript classes, the syntax changes I had to make were not significant. I don't want to go very much into detail regarding before and after since I believe it will be boring for most people. However, if you find it interesting, you could look at the diff of this pull request. Apart from renaming files with the .ts extension and changing the syntax, I had to install the necessary dependencies for types. Since I don't depend on many libraries, I didn't have to install many type packages. When installing type dependencies, always install them on the development dependencies. Similar to TypeScript, we don't need these dependencies when we have the built code.

npm i -D @types/node @types/express @types/body-parser

After I finished manually transpiling all the JavaScript code to TypeScript, I also turned strict mode on. However, the package greek-utils that I use in my code does not offer type declarations, and since it's not a very popular package, there are no types by DefinitelyTyped. Because of that, the compiler was complaining about not being able to find a declaration file for the specific module. I thought about creating one myself since the library is not very big, but that was out of scope. However, it's a good idea for a future post. In the end, I followed this post and created a file declaration file where I declared the module like this:

declare module 'greek-utils'

Of course, this is not a proper declaration of the module since we don't define any type, and the whole module will be of type any, but it's something the compiler will accept.
Moving on, I think the most interesting part was changing my linter.

Switching from TSLint to ESLint

So far, with all my Typescript projects, I was using tslint from Palantir with the recommended linting setup. However, as you may already know, the TSLint team decided to deprecate the library, move to ESLint and build typescript-eslint. The TSLint team decided to provide a unified way of linting JS/TS projects and benefit from the JS linting ecosystem. You can find more details regarding the decision and the future roadmap in this GitHub issue.

So for this project, I decided to use the new typescript-eslint package instead of TSLint. What's nice is that the TSLint team provides an npm package that will translate your tslint.json to an equivalent ESLint configuration file. That means I can take the tslint.json I usually use and convert it to an eslintrc.json.

{
    "defaultSeverity": "off",
    "extends": [
      "tslint:recommended"
    ],
    "linterOptions": {
      "exclude": [
        "./migrations/*"
      ]
    },
    "jsRules": {
      "no-unused-expression": true
    },
    "rules": {
      "quotemark": [
        true,
        "single"
      ],
      "member-access": [
        false
      ],
      "ordered-imports": [
        false
      ],
      "max-line-length": [
        true,
        150
      ],
      "member-ordering": [
        false
      ],
      "interface-name": [
        false
      ],
      "arrow-parens": false,
      "object-literal-sort-keys": false,
      "no-null-keyword": true,
      "no-console": false
    },
    "rulesDirectory": []
  }
Listing 1 - The tslint.json I normally use

To use the tslint-to-eslint-config I had to do the following:

First, I had to install TSLint. If this sounds weird to you, bear with me because we will remove it in the end, we only need it so that the tslint-to-eslint-config can perform the config translation.

npm i -D tslint

Remove the existing eslintrc.js since we want to generate a new one based on the tslint.json.

Add in the root directory the tslint.json we want to translate.

Run npx tslint-to-eslint-config in the root directory. This command will generate a new eslintrc.js that will be equivalent to the tslint.json we provided. You can take a look at the generated file here.

Add the necessary typescript-eslint plugins in the development dependencies:

npm i -D @typescript-eslint/parser @typescript-eslint/eslint-plugin

Remove the old eslint plugins from the development dependencies:

npm un -D eslint-config-airbnb-base eslint-plugin-import

Uninstall tslint and delete the tsconfig.json.

Finally, I made some changes to my setup too. I had to update my VSCode settings to use ESLint for TypeScript also:

{
  "[javascript]": {
      "editor.tabSize": 2,
      "editor.codeActionsOnSave": {
          "source.fixAll.eslint": true
      }
  },
  "[typescript]": {
      "editor.tabSize": 2,
      "editor.codeActionsOnSave": {
          "source.fixAll.eslint": true
      }
  },
  "eslint.alwaysShowStatus": true,
  "eslint.enable": true,
  "eslint.nodePath": "./node_modules/.bin/",
  "eslint.options": {
      "configFile": ".eslintrc.js"
  }
}

And I also added a linting script in my package.json:

"scripts": {
    ...
    "lint": "eslint . --ext .ts"
  },
linting-errors

Now you can go ahead and fix all the linting errors! :D

Summary

That was it for today, now the bot project is fully migrated to Typescript, and we can move on with development.

I hope you found this post informative! Stay in touch!

Subscribe to Backend Definite

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe