loading...
Cover image for How I set up my emacs for TypeScript

How I set up my emacs for TypeScript

viglioni profile image Laura Viglioni Updated on ・5 min read

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 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 was even better than rjsx-mode, all the types are shown perfectly in the bottom bar, autocomplete, auto-import... Everything. And thanks to tide. The sad part is: there is no tsx-mode, to write our .tsx files, we have to use web-mode. 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:

An important point here: I use nowadays spacemacs 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, import-js, 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:

(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)
 ;; ...
Enter fullscreen mode Exit fullscreen mode

see typescript layer, javascript layer, html layer

and on dotspacemacs-additional-packages

;; ...
 dotspacemacs-additional-packages
   '(
     rjsx-mode
     yasnippet-snippets
     prettier-js
     import-js
     ;; ...
Enter fullscreen mode Exit fullscreen mode

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

npm i -g tern prettier
npm install -g import-js
Enter fullscreen mode Exit fullscreen mode

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 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:

(defun dotspacemacs/user-config ()
 ;; ...
 ;; tide def func:
 (defun tide-setup-hook ()
    (tide-setup)
    (eldoc-mode)
    (run-import-js)
    (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)
 ;; ...
Enter fullscreen mode Exit fullscreen mode

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:

;; yasnippet
(yas-global-mode 1)

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

;; company-mode 
(global-company-mode)
Enter fullscreen mode Exit fullscreen 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:

(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)
Enter fullscreen mode Exit fullscreen mode

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

Add these lines to the files:

typescript-mode/.yas-parents

rjsx-mode
Enter fullscreen mode Exit fullscreen mode

web-mode/.yas-parents

rjsx-mode
prog-mode
js-mode
Enter fullscreen mode Exit fullscreen 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: 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:

(sp-use-paredit-bindings)
Enter fullscreen mode Exit fullscreen mode

I also use neotree with all-the-icons to create my sidebar. Since this text is already too long, I will write about this specific config another day :)

And prettify symbols too!

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

This 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 :)

Posted on by:

viglioni profile

Laura Viglioni

@viglioni

Passionate about functional programming and pure mathematics

Discussion

pic
Editor guide
 

Any chance for vue+typescript, this really sad that vue-mode is no longer develop ;(

 

ooh :(
I never used vue :(