Problem
Lua is a highly dynamic language, and many real-world Lua frameworks mutate object capabilities at runtime.
This pattern is especially common in:
- game engines
- UI frameworks
- ECS architectures
- builder APIs
- runtime mixin systems
- userdata bindings from native engines
Currently, LuaLS/LuaCats cannot properly express:
"after calling this method, self now has additional capabilities/methods"
This becomes a major DX limitation for frameworks that dynamically extend objects.
Real-world Example
Consider a UI framework where all elements start as a generic UIElement.
---@class UIElement
local UIElement = {}
Calling:
injects image-related functionality into the element at runtime:
However, LuaLS still sees element as only UIElement.
The only current workaround is manual casting:
element:setupUIImage()
---@cast element UIImage
element:setImage(material)
This works technically, but becomes repetitive and hurts DX significantly in large codebases.
Comparison to TypeScript
TypeScript supports type refinement after method calls through assertion signatures such as:
This allows APIs to safely refine object types after capability-changing methods.
A good real-world example is discord.js, where Interaction objects can be refined into subtypes through methods like:
interaction.isButton()
interaction.isChatInputCommand()
After refinement, TypeScript understands the new subtype automatically.
Lua frameworks often use similar runtime patterns, but LuaLS currently cannot model them.
Proposed Solution
Introduce a LuaCats annotation for self-type refinement / capability injection.
Possible syntax examples:
---@injects UIImage
function UIElement:setupUIImage() end
or:
---@mutates self UIImage
function UIElement:setupUIImage() end
or:
---@becomes UIImage
function UIElement:setupUIImage() end
Expected Behavior
After:
LuaLS would understand:
element :: UIElement & UIImage
allowing:
without requiring manual casts.
Why This Matters
This would greatly improve support for:
- dynamic Lua architectures
- runtime capability injection
- engine bindings
- UI frameworks
- builder APIs
- fluent APIs
- mixin systems
while keeping Lua's dynamic nature intact.
This feature would also reduce:
- repetitive
---@cast
- noisy annotations
- inaccurate supersets in base classes
- degraded autocomplete quality
Additional Notes
This feature does not need to become full typestate analysis or advanced dependent typing.
Even a pragmatic flow-sensitive refinement system limited to:
- direct method calls
- current scope
- explicit annotations only
would already provide massive DX improvements.
Example Use Case
---@class UIImage
---@field setImage fun(self: UIImage, material: string)
---@class UIElement
---@injects UIImage
function UIElement:setupUIImage() end
local element = UIElement.new()
element:setupUIImage()
element:setImage("icon")
Expected:
- autocomplete works
- diagnostics recognize
setImage
- no manual cast required
Thanks for all the amazing work on LuaLS and LuaCats.
This would significantly improve tooling support for dynamic Lua patterns commonly used in real-world frameworks and game engines.
Problem
Lua is a highly dynamic language, and many real-world Lua frameworks mutate object capabilities at runtime.
This pattern is especially common in:
Currently, LuaLS/LuaCats cannot properly express:
This becomes a major DX limitation for frameworks that dynamically extend objects.
Real-world Example
Consider a UI framework where all elements start as a generic
UIElement.Calling:
injects image-related functionality into the element at runtime:
However, LuaLS still sees
elementas onlyUIElement.The only current workaround is manual casting:
This works technically, but becomes repetitive and hurts DX significantly in large codebases.
Comparison to TypeScript
TypeScript supports type refinement after method calls through assertion signatures such as:
This allows APIs to safely refine object types after capability-changing methods.
A good real-world example is
discord.js, whereInteractionobjects can be refined into subtypes through methods like:After refinement, TypeScript understands the new subtype automatically.
Lua frameworks often use similar runtime patterns, but LuaLS currently cannot model them.
Proposed Solution
Introduce a LuaCats annotation for self-type refinement / capability injection.
Possible syntax examples:
or:
or:
Expected Behavior
After:
LuaLS would understand:
allowing:
without requiring manual casts.
Why This Matters
This would greatly improve support for:
while keeping Lua's dynamic nature intact.
This feature would also reduce:
---@castAdditional Notes
This feature does not need to become full typestate analysis or advanced dependent typing.
Even a pragmatic flow-sensitive refinement system limited to:
would already provide massive DX improvements.
Example Use Case
Expected:
setImageThanks for all the amazing work on LuaLS and LuaCats.
This would significantly improve tooling support for dynamic Lua patterns commonly used in real-world frameworks and game engines.