My lspconfig works fine with typescript files, but not with Javascript.

  • Autocomplete shows .constructor and other standard props/methods instead of the expected ones defined on the type enter image description here
  • This happens even though the correct type is set (through jsdoc) or inferred from imported typescript modules enter image description here
  • If I simply set the filetype to typescript (:set ft=typescript), it starts working enter image description here

I used the Array class in the example, but the issue is the same with user-defined types, even when the type definition is written using jsdoc.

How can I make autocomplete work as expected with Javascript files too?

Note: I use native LSP only, other plugins like nvim-cmp and coq-nvim work as expected, but I prefer to avoid them. Since they all use LSP, I suppose I am misconfiguring something.

My relevant configs:


" LSP config
set omnifunc=v:lua.vim.lsp.omnifunc
set tagfunc=v:lua.vim.lsp.tagfunc

" open LSP definition
map <F9> :lua vim.lsp.buf.hover()<CR>
inoremap <F9> <C-o>:lua vim.lsp.buf.hover()<CR>

" go to definition
map <F12> :lua vim.lsp.buf.definition()<CR>
inoremap <F12> <C-o>:lua vim.lsp.buf.definition()<CR>

" code completion with omni function
inoremap <C-Space> <C-x><C-o>
inoremap <C-@> <C-x><C-o>


-- LSP config
local lspconfig = require('lspconfig')
local servers = { 'bashls', 'sumneko_lua', 'solargraph', 'tsserver', 'vimls' }
for _, lsp in ipairs(servers) do

Full config files:

Output of :LspInfo

 Language client log: /home/diovani/.cache/nvim/lsp.log
 Detected filetype:   javascript
 2 client(s) attached to this buffer: 
 Client: tsserver (id: 1, pid: 114182, bufnr: [1])
    filetypes:       javascript, javascriptreact, javascript.jsx, typescript, typescriptreact, typescript.tsx
    autostart:       true
    root directory:  /home/diovani/Development/Node/interactive-pbta-bot
    cmd:             typescript-language-server --stdio
 Client: null-ls (id: 2, pid: 5001, bufnr: [1])
    filetypes:       typescriptreact, typescript, javascriptreact, javascript, vue, lua, ruby, sh, less, scss, sass, css, yaml, json
    autostart:       false
    root directory:  /home/diovani/Development/Node/interactive-pbta-bot
    cmd:             nvim
 Configured servers list: bashls, sumneko_lua, solargraph, tsserver, vimls
  • 1
    Given that there's a tsserver in there, it may only be getting set up for typescript files. Also, consider that a JS LSP can only do so much (like imported functions) because of all the dynamic "stuff"
    – D. Ben Knoble
    Commented Jul 18, 2022 at 19:19
  • 1
    [update] I included the output of :LspInfo Commented Jul 18, 2022 at 20:29
  • What is weird is that it is not correctly showing completions even for some native classes. Object and Array does not work. Math does. :/ Commented Jul 18, 2022 at 20:31

1 Answer 1


I found the solution in this reddit post: https://www.reddit.com/r/neovim/comments/rs47cx/tsserver_and_vimlspomnifunc/.

Neovim comes with its built-in javascript autocomplete which was overriding the omnifunc.

To check if that is happening, open a Javascript file and type:

set omnifunc?

if the result is omnifunc=javascriptcomplete#CompleteJS it is using the built-in autocomplete.

The solution is to set omnifunc (and keymaps, if any) on the attach event of the LSP servers setup, as suggested in lsp_config docs.

Note: you must pass the defined on_attach as an argument to every setup {} call and the keybindings in on_attach only take effect on buffers with an active language server.

Here is my final configuration, finally working:

-- LSP config
local lspconfig = require('lspconfig')
local servers = { 'bashls', 'sumneko_lua', 'solargraph', 'tsserver', 'vimls' }
for _, lsp in ipairs(servers) do
    on_attach = function(_, bufnr)
      vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc')
      vim.api.nvim_buf_set_option(bufnr, 'tagfunc', 'v:lua.vim.lsp.tagfunc')
  • I'm intrigued as to how LSP works with a non typed language.
    – RichieHH
    Commented Nov 1, 2023 at 5:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.