Dalius's blog

Wednesday, August 3, 2022

Typescript and Neovim LSP

I have found good reasons to migrate from Ale to Neovim LSP for Typescript development. At least one problem is still not solved, but the pros outweigh minor inconveniences. I will review tools I am using and will explain some details that are not obvious.

You can find my vim configuration here: github.com/daliusd/cfg/blob/master/.vimrc


I use following plugins:

  • neovim/nvim-lspconfig
  • jose-elias-alvarez/null-ls.nvim
  • jose-elias-alvarez/typescript.nvim
  • hrsh7th/nvim-cmp

Each plugin has detailed documentation so I will cover what might be different in my configuration and will do little comparison with Ale.


nvim-lspconfig is almost perfect out-of-the-box but I have preference to review all the results by opening files (instead having them listed in quickfix window). To fix this I am using on_list override. As well there is typescript-language-server bug that needs some filtering. This is excerpt from my config that addresses these two problems:

local function on_list(options)
  -- https://github.com/typescript-language-server/typescript-language-server/issues/216
  local items = options.items
  if #items > 1 then
    items = filter(items, filterReactDTS)

  vim.fn.setqflist({}, ' ', { title = options.title, items = items, context = options.context })


  vim.keymap.set('n', '<leader>ad', function() vim.lsp.buf.declaration{on_list=on_list} end, bufopts)
  vim.keymap.set('n', '<leader>d', function() vim.lsp.buf.definition{on_list=on_list} end, bufopts)
  vim.keymap.set('n', '<leader>ai', function() vim.lsp.buf.implementation{on_list=on_list} end, bufopts)
  vim.keymap.set('n', '<leader>at', function() vim.lsp.buf.type_definition{on_list=on_list} end, bufopts)
  vim.keymap.set('n', '<leader>af', function() vim.lsp.buf.references(nil, {on_list=on_list}) end, bufopts)

After this Neovim LSP is better than Ale because of following:

  • If there is more than one error on the line you can review them all. In Ale you can see one at the time.

  • Hover/Auto-complete information shows more details than Ale.

Other functionality is more or less the same. The only advantage of Ale that it uses tsserver directly. No need for typescript-language-server.


null-ls.nvim was a pleasant find if compared to Ale. It has good documentation, supports all the tools I need (like Ale) and has code actions for software without language server (e.g. eslint_d or git).


For complete Typescript experience you might want to install this as well.


For autocomplete I am using this plugin as it is reasonably fast and allows me to config completion the way I want to (including look and emoji support 🥳). So I am not losing anything what I was getting from deoplete.

Complain about typescript-language-server

My main complain about Neovim LSP was that I need to install typescript-language-server while Ale works with tsserver directly. I found out that I am installing multiple node packages because of Neovim anyway so one more is not the problem. E.g. my current list look like this:

npm install -g neovim
npm install -g write-good
npm install -g vim-language-server
npm install -g typescript-language-server
npm install -g eslint_d

So in the end I recommend using Neovim LSP over Ale for Typescript development. These are minor improvements overall but that might be major productivity improvement in the end.