Vue 3 & TypeScript in Neovim

Making them work together with hints and autocomplete

RÉMINO Bits

If you’re like me, you prefer Vue over React, Neovim over VSCode, and you have a love-hate relationship with TypeScript. The pain you must go through to have Neovim work efficiently with Vue 3 and TypeScript isn’t helping either.

I’ll spare any long-winded tale about how much hang-banging there was to make it all work. Long story short, the Volar 2 Vue language server no longer has TypeScript support built in. So, with it, you have to use the ts_ls TypeScript LSP, a.k.a. typescript-language-server. (Yeah, the names and aliases throw me off too.)

Let’s just jump into the Neovim config I had to put it to have them play together peacefully, marching together hand in hand towards peace.

The LSP config

Keep in mind, I forked an NvChad starter config with which does some things automatically, like loading mappings and pre-made LSP configs.

-- ~/.config/nvim/lua/configs/lspconfig.lua
-- Loaded automatically by NvChad

-- Load defaults i.e lua_lsp
require("nvchad.configs.lspconfig").defaults()

local lspconfig = require "lspconfig"
local nvlsp = require "nvchad.configs.lspconfig"

-- Dynamically point to the path of @vue/language-server
-- which contains @vue/typescript-plugin
local vue_typescript_plugin =
	vim.fn.expand(vim.fn.stdpath "data" .. "/mason/packages/vue-language-server/node_modules/@vue/language-server")

-- Set up ts_ls LSP with @vue/typescript-plugin
lspconfig.ts_ls.setup {
	on_attach = nvlsp.on_attach,
	on_init = nvlsp.on_init,
	capabilities = nvlsp.capabilities,
	init_options = {
		plugins = {
			{
				name = "@vue/typescript-plugin",
				location = vue_typescript_plugin,
				languages = { "vue" },
			},
		},
	},
	filetypes = {
		"javascript",
		"typescript",
		"vue",
	},
	settings = {
		typescript = {
			tsserver = {
				useSyntaxServer = false,
			},
			inlayHints = {
				includeInlayParameterNameHints = "all",
				includeInlayParameterNameHintsWhenArgumentMatchesName = true,
				includeInlayFunctionParameterTypeHints = true,
				includeInlayVariableTypeHints = true,
				includeInlayVariableTypeHintsWhenTypeMatchesName = true,
				includeInlayPropertyDeclarationTypeHints = true,
				includeInlayFunctionLikeReturnTypeHints = true,
				includeInlayEnumMemberValueHints = true,
			},
		},
	},
}

The config above was inspired by the official