How I set up my emacs for TypeScript + React
Tags: typescript, react, emacs, javascript
Published: 2020-10-11 20:32:51

# What exactly is my point here?

I recently knew typescript and with it, some joy and some tears. For a very long time, I've been working with React and using an emacs mode called [rjsx-mode](https://github.com/felipeochoa/rjsx-mode) and I always loved it, I think this is a mode so good I use it even with regular JavaScript files.

Then I started with TypeScript and I was both amazed and saddened by it. For regular TS files, `.ts` it was amazing. The spacemacs [typescript-mode](https://develop.spacemacs.org/layers/+lang/typescript/README.html) was even better than `rjsx-mode`, all the types are shown perfectly in the bottom bar, autocomplete, auto-import... Everything. And thanks to [tide](https://github.com/ananthakumaran/tide). The sad part is: there is no `tsx-mode`, to write our `.tsx` files, we have to use [web-mode](http://web-mode.org/). Don't get me wrong, this is a great mode, but `React + Typescript` were not the goals back then.

My point here is to put the best parts of all three modes in all of them!

This text might be a little long, but I hope it will help :)

Here my configs in practice:
{%youtube Q29ZhIYe6iY%}

> An important point here: I use nowadays [spacemacs](https://www.spacemacs.org/) and part of my code examples here will be in its way of doing things, but there is no magic, spacemacs is just emacs with some already written extra lisp (haha). You will be able to do it in your other emacs. But I **really** recommend you to start with spacemacs, especially if you are new to emacs. Changed my life, but this is a theme for another text.

# Let's get started 

You must have some modes installed. If you are using spacemacs most of them will be installed automatically when you install the layers. Those packages are:
`rjsx-mode`, `typescript-mode`, `web-mode`, `tide`, `company`, `yasnippet`, `prettier-js` (sorry if I forgot to list some pkg here)

Or in a simpler way, on your `.spacemacs` file add these layers on `dotspacemacs-configuration-layers`:

```elisp
(defun dotspacemacs/layers ()
  ;; ... 
  dotspacemacs-configuration-layers
   '(
     html
     (typescript :variables
                 javascript-backend 'tide
                 typescript-fmt-tool 'prettier
                 typescript-linter 'eslint)
     (javascript :variables
                 javascript-backend 'tide
                 javascript-fmt-tool 'prettier
                 node-add-modules-path t)
 ;; ...
```
see [typescript layer](https://develop.spacemacs.org/layers/+lang/typescript/README.html), [javascript layer](https://develop.spacemacs.org/layers/+lang/javascript/README.html), [html layer](https://develop.spacemacs.org/layers/+lang/html/README.html#prettier)

and on `dotspacemacs-additional-packages`
```elisp
;; ...
 dotspacemacs-additional-packages
   '(
     rjsx-mode
     yasnippet-snippets
     prettier-js
     ;; ...
```

Some of these imports require you to install third-party libs:

```shell
npm i -g tern prettier
```
If you are not using spacemacs, you must to require each package on your `.emacs` file. All the GitHub pages of these modes have clear instructions for the installation :)

# Applying `tide` to `rjsx` and `web` modes
The basics configs are done, we have all the three modes installed and working, what now? 

[Tide](https://github.com/ananthakumaran/tide) is a great mode that does a lot of magic for you, I'd recommend you to read its README. It runs automatically on `typescript-mode` and it would be great to use it on your other `js/ts` modes.

I have all my config files separated and import them in `dotspacemacs/user-config`, but you can put all these extra configs directly on this section or on your `.emacs` file if you're not using spacemacs.

First, we define a tide function config, later apply it on all those modes:

```elisp
(defun dotspacemacs/user-config ()
 ;; ...
 ;; tide def func:
 (defun tide-setup-hook ()
    (tide-setup)
    (eldoc-mode)
    (tide-hl-identifier-mode +1)
    (setq web-mode-enable-auto-quoting nil)
    (setq web-mode-markup-indent-offset 2)
    (setq web-mode-code-indent-offset 2)
    (setq web-mode-attr-indent-offset 2)
    (setq web-mode-attr-value-indent-offset 2)
    (setq lsp-eslint-server-command '("node" (concat (getenv "HOME") "/var/src/vscode-eslint/server/out/eslintServer.js") "--stdio"))
    (set (make-local-variable 'company-backends)
         '((company-tide company-files :with company-yasnippet)
           (company-dabbrev-code company-dabbrev))))

;; hooks
(add-hook 'before-save-hook 'tide-format-before-save)


;; use rjsx-mode for .js* files except json and use tide with rjsx
(add-to-list 'auto-mode-alist '("\\.js.*$" . rjsx-mode))
(add-to-list 'auto-mode-alist '("\\.json$" . json-mode))
(add-hook 'rjsx-mode-hook 'tide-setup-hook)


;; web-mode extra config
(add-hook 'web-mode-hook 'tide-setup-hook
          (lambda () (pcase (file-name-extension buffer-file-name)
                  ("tsx" ('tide-setup-hook))
                  (_ (my-web-mode-hook)))))
(flycheck-add-mode 'typescript-tslint 'web-mode)
(add-hook 'web-mode-hook 'company-mode)
(add-hook 'web-mode-hook 'prettier-js-mode)
(add-hook 'web-mode-hook #'turn-on-smartparens-mode t)
 ;; ...
```
These last lines add our tide setup for `.tsx` files and some other sub-modules that already exists in the other two modes.

Also, I recommend using these modes globally:
```elisp
;; yasnippet
(yas-global-mode 1)

;; flycheck
(global-flycheck-mode)
(add-hook 'after-init-hook #'global-flycheck-mode)

;; company-mode 
(global-company-mode)
```

# Using `rjsx` snippets on all three modes
The one thing `rjsx-mode` has better than the other two modes is its snippets, so let's use it everywhere :)

There are two ways here, the first you can find on your `.emacs.d` where is the default dir for snippets configs (on spacemacs is `.emacs.d/layers/+completion/auto-completion/local/snippets/`), the second is define your own:

```elisp
(add-to-list 'yas-snippet-dirs "~/path/to/your/dir")
;; notice that this add-to-list must be called before this:
(yas-global-mode 1)
```
The procedure here is very simple: inside your snippet dir, create a dir with the mode name, i.e. `web-mode/` and inside it create a file called `.yas-parents` with the mode names you want to "steal" the snippets. In our case:
> snippets-dir/

>> web-mode/
>>> .yas-parents

>> typescript-mode/
>>> .yas-parents

On my own configs:
![Picture of these dirs in a tree](https://dev-to-uploads.s3.amazonaws.com/i/tuqkk04dwiktgsjsgyb0.png)

Add these lines to the files:

`typescript-mode/.yas-parents`
```text
rjsx-mode
```

`web-mode/.yas-parents`
```text
rjsx-mode
prog-mode
js-mode
```

# Last but not least
With all these configs you're now able to auto-import, format/import on saving, check types, check definitions... Everything :)

But I'd like to recommend you another package called [paredit](http://wikemacs.org/wiki/Paredit-mode): it is a lib for lisp languages (if you are coding in any lisp family this package should be mandatory!) but once you get the shortcuts, you want to use them in every language, it is possible with this function call:

```elisp
(sp-use-paredit-bindings)
```

I also use [neotree](https://github.com/jaypei/emacs-neotree) with [all-the-icons](https://github.com/domtronn/all-the-icons.el) to create my sidebar. Since this text is already too long, I will write about this specific config another day :)

And [prettify symbols](https://emacsredux.com/blog/2014/08/25/a-peek-at-emacs-24-dot-4-prettify-symbols-mode/#:~:text=Emacs%2024.4%20ships%20with%20a,would%20replace%20several%20ascii%20characters) too!

I really hope you liked it and I hope this to be useful to you on your emacs journey.

[This](https://github.com/Viglioni/spacemacs) is my spacemacs config repo, all my lisps are in `laurisp/` (haha) dir.

Be safe, use masks, stay home, use emacs.
xoxo



edit: _I've found today some strange behaviour of `import-js` so I removed it from this tutorial. I'll try using tide for organizing imports on save, if I'm successful I update it here :)_