LuaLS / LuaLS/lua-language-server

How do I document a generic class (JS Promises)

Open
#1,532 4 comments 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement feat/generic
Dominant language
Lua
Stars
4.4k
Forks
442
PR merge metrics
No merged PRs in 30d

Description

Hello everyone! First of all, thank you for the amazing work on this server. It's really great and extremelly fast to use!

I've a question about how can I use the type system to properly type a Promise-like table that I'm creating. Right now I need to type this piece of code:

local Promise = require ".../promise"
Promise:new(function(resolve, reject)
  -- do some async stuff...
  if some_async_true_status then
    resolve(some_async_result)
  else
    reject(some_async_error)
  end
end):next(function(result) -- < `resolve()` value here
  print(result)
end):catch(function(err) -- < `reject()` value here
  print(err)
end)

This a Promise-like implementation that I'm doing for my neovim plugin which I'm trying to get a similar API as the Javascript Promise.

My question here is, how can I type this to the callee function knows what this is going to be returned from that callback? Currently, I'm trying to play around with @generic but, I can't get the server to properly understand what I mean by my types:

local Promise = {}

---@generic T
---@class Promise<T>
---@field new(executor: fun(resolve: fun(result: T), reject: fun(err: any)))): Promise
---@field next(fn: fun(result: T)): Promise <<<<< here I'm returning `self`
---@field catch(fn: fun(err: any)): Promise <<<<< here I'm returning `self` as well

function Promise:new(executor)
  local promise = { ... }
  -- ... some operations
  return setmetatable(promise, {
    __index = self,
  })
end

function Promise:next(fn)
  -- some operations...
  return self
end

function Promise:catch(fn)
  -- some operations...
  return self
end

----------------------
-- Here is how I want to use it:

---@return Promise<string>
function my_function_that_return_promise()
  return Promise:new(function(resolve, reject)
    -- .....
    resolve("hello")
  end)
end

my_function_that_return_promise():next(function(result)
  print(result) -- << here I want the server to show `result` is a `string`
end)

For reference, this is how we can do this exactly thing using typescript:

const myPromise = new Promise<string>((resolve, reject) => {
  // ...
  resolve("hello")
})

myPromise
  .then((result) => console.log(result)) // < `result` will have `string` type
  .catch((err) => console.log(err))

Thank you for the awesome work! Sorry if I didn't make myself clear, let me know if I need to provide any further information.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the @generic and @class annotations in the Promise example and trace how the language server currently infers callback types through new(), next(), and catch(). Done means determining whether the requested generic propagation is supported or requires a defined type-system change, with the string result inferred in the final callback.

Written by the indexing model from the issue text.

Assessment

Tech stack
lua, neovim
Domain
devtools
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.