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
, 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)
;; ...
see typescript layer, javascript layer, html layer
and on dotspacemacs-additional-packages
;; ...
dotspacemacs-additional-packages
'(
rjsx-mode
yasnippet-snippets
prettier-js
;; ...
Some of these imports require you to install third-party libs:
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 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)
(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:
;; 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:
(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
Add these lines to the files:
typescript-mode/.yas-parents
rjsx-mode
web-mode/.yas-parents
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: 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)
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 :)
Top comments (16)
Hi,
Taking for reference your video, at the second 00:10 you import map and when you accept the auto-complete and it automatically add the import on the top.
in vscode and neovim on both I manage to do that, but i don't know what i'm doing wrong to not making work that feature in spacemacs.
What tool or configuration make possible to achieve that?
It's a Typescript React environment
Thanks a lot
Hi David,
import-js
is what you're looking for github.com/Galooshi/emacs-import-j...I had problems with import-js, that's why I removed from this text. Tide should be enough for auto importing 🤔
I'm sorry for the delay if I'm not mistaken the company package does that.
If it helps those are my configs about js/ts:
github.com/Viglioni/spacemacs/blob...
github.com/Viglioni/spacemacs/blob...
github.com/Viglioni/spacemacs/blob...
Starting Emacs 29.1, there is the built-in
tsx-ts-mode
major mode for editing Typescript + JSX. You could also be interested by jtsx package that extendstsx-ts-mode
(andjs-ts-mode
too) to provide some handy additional functionalities.why not lsp though? I'm confused about the fact that the major-mode shown is web, instead of React (which is a layer too). you can force that mode doing M-x and then
rjsx-mode
.Yes! I'm trying lsp now and i think it is great, I will soon write a text about my TS config with LSP :)
it is quite easier than with tide and better.
Hi. Please write that text! I am configuring now and need some assitance. Thanks for writing the first post also.
This is the perfect tutorial I have been looking for, thank you
thx!
Great stuff!
thx!
Any chance for vue+typescript, this really sad that vue-mode is no longer develop ;(
ooh :(
I never used vue :(
Hi Laura, why do you need import-js. Doesn't Tide do auto-import already?
As a matter of fact yes! I used to format imports on save, but it is not necessary :)