LuaLS / LuaLS/lua-language-server

[Feature Request] Implement additional helper types

未关闭
#2,817 17 条评论 13 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

enhancement feat/LuaCats Annotations
主要语言
Lua
星标
4.4k
派生
442
PR 合并指标
30 天内没有已合并 PR

描述

[!NOTE]
Just a heads up, this is gonna be a lengthy issue.

Summary

I would like to see some helper types get implemented, which would simplify writing more complex type annotations. Some of these could probably be implemented just using existing LuaCATS syntax, but others most likely need special support directly embedded into LuaLS.

This issue includes markers to track which feature is implemented and which isn't.

The types in question

  • never: Marks a function as not returning anything, and marks storing its value as an error (unlike @returns nil).
  • Keys<T: table<K, V>>: Extracts K, may create a union type
  • Values<T: table<K, V>>: Extracts V, may create a union type
  • NonNilable<T>: Removes nil from the union type T, making a value as required.
  • Partial<T>: Returns a copy of type/class T, but with each field marked as optional / nilable.
  • Required<T>: The opposite of Partial<T>, marking all fields as required / non-nilable.
  • Exclude<T, U>: Remove all types in the union U from the union T
  • FunctionParameters<T: fun(...)>: Get the parameter names and types of a function.
  • TypeParameters<T>: Returns a tuple of all type parameters passed T

Notes and examples

  • TypeParameters<SomeGenericType<string, integer[], boolean>> a tuple [string, integer[], boolean]

  • Keys<T> and Values<T> a union type if the keys / values can have multiple types. In other words:

    • Keys<{ foo: "abc", bar: "xyz" }> should give the type "foo"|"bar"
    • Values<{ foo: "abc", bar: "xyz" }> should give the type "abc"|"xyz"
  • The Partial-type should work like this:

    Input:

    Partial<{
        user_name: string,
        email_address: string,
        verified: boolean,
        extra_data?: table<string, Any>
    }>
    

    Output:

    {
        user_name?: string,
        email_address?: string,
        verified?: boolean,
        extra_data?: table<string, Any>
    }
    
  • FunctionParameters<fun(name: string, age: integer)> should give the type { name: string, age: integer }

    • If someone only needs the parameter names, they may use Keys<FunctionParameters<T>>
  • never is useful for communicating to users of a marked function that its return values may change in the future. This is primarily used to communicate to other maintainers / your future self that they / you can change this if they / you want.

  • Exclude<T, U> should only remove types from T that it can actually find in U. For example:

    • Exclude<string|number|boolean|function, number|boolean> should give the type string|function
    • Exclude<string|number|boolean, function|userdata> should give the type string|number|boolean, as neither function nor userdata are in T

Implementation

These types would most likely require implementing some features from TypeScript:

  • Conditional types (The TS syntax is predicate ? T : U, but if predicate then T else U would probably fit in better with Lua, and potentially allow for elseif down the line if deemed to be necessary or just a good addition; plus, LuaCATS already uses : as the inheritance-operator and ? as the optional/nilable-operator). Examples:
    • ---@alias HasFourLegs<Animal> if Animal : { leg_count: 4 } then Animal else never
      ---@alias FourLeggedAnimals HasFourLegs<Bird|Dog|Ant|Wolf> --> Dog|Wolf
      
  • Type indexing. Examples:
    • The first type of the tuple [string, number, boolean] could be accessed with [string, number, boolean][1]
    • The third parameter name biz of the function fun(foo, bar, biz, baz) could be retrieved with Keys<FunctionParameters<fun(foo, bar, biz, baz)>>[3]
    • The type of the biz field of the table {foo: "bar", biz: "baz"} could be accessed with {foo: "bar", biz: "baz"}["biz"]

Alternatively, instead of fully implementing these features, it might be enough to "simply" hard-code types like Keys and Values. It might also be a good idea to investigate allowing to write types in Lua (perhaps via plug-ins) instead.

If these are not implemented via hard-coding, the following keywords from TypeScript would most likely have to be implemented as well

  • in (for collection-like types)
  • keyof

Once that's all done, some of them could be the implemented like this:

--- These were partially taken and adapted from the TypeScript docs, see:
--- https://www.typescriptlang.org/docs/handbook/utility-types.html

---@alias Keys<T> keyof T
---@alias Values<T> T[keyof T]

--- ...

---@alias NonNilable<T> if T : nil then never else T
---@alias Partial<T> { [P in Keys<T>]?: T[P]|undefined }
---@alias Required<T> { [P in keyof T]: NonNilable<T[P]> }
---@alias Exclude<T, U> if T : U then never else T
--- Not sure how this would be implemented...
---@alias FunctionParameters<T> ???
--- Same goes for this...
---@alias TypeParameters<T> ???

Considerations

I am decently familiar with LPEG grammars, so I could probably help make all of this happen if given some pointers in the right directions.

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

未指定源文件或测试。先阅读现有的 LuaCATS 类型语法和 LPEG 语法区域,然后确定哪些辅助类型和实现策略已获得维护者共识。完成应意味着实现了一个明确限定范围的子集,并覆盖其文档中的示例;目前,该 issue 对这一范围仍未作出限定。

由索引模型根据 Issue 内容生成。

评估

技术栈
lua
领域
devtools, tooling
Issue 类型
功能
难度
5/5
预计耗时
一周以上
活跃度
冷清
描述清晰度
需要澄清
新手友好度
25/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。