TypeScript (+tsx) mode for Emacs.

It has been a while since I did much development with React. Last time I had a good setup I was using VSCode. But, I wanted to do some work with it so I took some time to get a good Emacs setup.

The React docs now mention to use a tool like Next.js on top of React (some great fodder for another article...). So, I setup Next.js and the default config is TypeScript. Of course, Emacs doesn't have great support for TypeScript out of the box. I briefly felt the pang of wanting to switch back to VSCode. But, I dug in and decide to make it work in Emacs. Below are my notes on how you too can get it setup.

I've done the following procedure successfully on an M2 Macbook. An Intel Mac probably won't require anything different. For Linux you'll have to use your OS's package manager (I use homebrew below) but the rest should work the same. No clue about other systems.

Compile Emacs with Tree Sitter

Mastering Emacs has a wonderful article on how to get Emacs with Tree Sitter support as well as some background on Tree Sitter. I copied quite a bit of my install directly from that article.

Emacs has Tree Sitter support but it isn't enabled by default (as of writing). So, you'll likely need to compile Emacs from source with Tree Sitter enabled:

#!/bin/bash
set -eou pipefail

brew install wget
cd ~
declare v='29.4' # In 29 emacs has tree sitter support but need to be compiled with it
if [[ ! -f "emacs-$v.tar.gz" || ! -d "emacs-$v" ]]; then
    wget "https://ftp.gnu.org/pub/gnu/emacs/emacs-$v.tar.gz"
    tar -zxf "emacs-$v.tar.gz"
fi
cd "emacs-$v"
# Install adapted from https://www.adventuresinwhy.com/post/compiling-emacs-with-tree-sitter/
brew install \
    autoconf \
    gcc \
    giflib \
    gnutls \
    imagemagick \
    jansson \
    jpeg \
    libgccjit \
    libpng \
    librsvg \
    libtiff \
    texinfo \
    tree-sitter
CC=gcc-12 ./autogen.sh
# --with-tree-sitter is all you really need. I like the rest so I can view images.
# --with-native-comilation=aot used to really speed up Emacs but the effects seem
# to diminish with every release. Still can't hurt.
CPPFLAGS="-I/opt/homebrew/opt/jpeg/include" LDFLAGS="-L/opt/homebrew/opt/jpeg/lib" ./configure \
    --with-gif \
    --with-imagemagick \
    --with-jpeg \
    --with-native-compilation=aot \
    --with-png \
    --with-rsvg \
    --with-tiff \
    --with-tree-sitter \
    --with-x-toolkit=gtk3 \
    --with-xwidgets
make install
mv nextstep/Emacs.app /Applications

Okay. You should now be able to run the Emacs app.

Adding tsx-mode.el

I'm using tsx-mode.el to add a major mode for TypeScript in Emacs. To install it you'll need to:

cd emacs.d # Whever you keep your .el files
# Add to your init.el.
cat >> init.el <<'EOF'
;; Enables downloading of grammars for different languages
(setq treesit-language-source-alist
   '((bash "https://github.com/tree-sitter/tree-sitter-bash")
     (cmake "https://github.com/uyha/tree-sitter-cmake")
     (css "https://github.com/tree-sitter/tree-sitter-css")
     (elisp "https://github.com/Wilfred/tree-sitter-elisp")
     (go "https://github.com/tree-sitter/tree-sitter-go")
     (html "https://github.com/tree-sitter/tree-sitter-html")
     (javascript "https://github.com/tree-sitter/tree-sitter-javascript" "master" "src")
     (json "https://github.com/tree-sitter/tree-sitter-json")
     (make "https://github.com/alemuller/tree-sitter-make")
     (markdown "https://github.com/ikatyang/tree-sitter-markdown")
     (python "https://github.com/tree-sitter/tree-sitter-python")
     (toml "https://github.com/tree-sitter/tree-sitter-toml")
     (tsx "https://github.com/tree-sitter/tree-sitter-typescript" "master" "tsx/src")
     (typescript "https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src")
     (yaml "https://github.com/ikatyang/tree-sitter-yaml")))
(require 'tsx-mode)
(add-to-list 'auto-mode-alist '("\\.[jt]s[x]?\\'" . tsx-mode))
EOF
wget https://raw.githubusercontent.com/orzechowskid/tsx-mode.el/refs/heads/main/tsx-mode.el
wget https://raw.githubusercontent.com/orzechowskid/tree-sitter-css-in-js/refs/heads/main/css-in-js-mode.el
M-x package-install coverlay origami corfu # Deps of tsx-mode
npm install -g typescript-language-server # Language server eglot will use
M-x treesit-install-language-grammar typescript # Install the TypeScript grammar

Profit

Not too bad when the instructions are set out like this. But, it took me an evening to figure out how to string all of the pieces together. You should now be able to open a .tsx file and have tsx-mode provide a nice major mode for working with the file.