LuaLS type annotations
Lua’s dynamic nature makes it incredibly flexible, but this flexibility can sometimes lead to hard-to-debug type errors. The Lua Language Server (LuaLS) introduces a powerful type annotation system called LuaCATS (Lua Comment And Type System) that brings type safety and intelligent code assistance to Lua development.
What are LuaLS Annotations?
Section titled “What are LuaLS Annotations?”LuaLS annotations are special comments prefixed with ---
(three dashes) that provide type information to the language server. These annotations help the server understand your code better, enabling features like:
- Type checking and error detection
- Intelligent autocompletion
- Better signature help
- Code navigation and documentation
- Refactoring support
Basic Syntax and Formatting
Section titled “Basic Syntax and Formatting”Annotations use triple-dash comments and support Markdown formatting:
--- This is a basic annotation------ **Bold text** and *italic text* are supported
Core Type System
Section titled “Core Type System”LuaLS recognizes all standard Lua types, such as nil
, any
, boolean
, string
, and more.
Advanced Type Expressions
Section titled “Advanced Type Expressions”Type Pattern | Example | Description |
---|---|---|
Union Type | string|number | Multiple possible types |
Array | string[] | Array of specific type |
Dictionary | { [string]: boolean } | String-keyed dictionary |
Key-Value | table<KEY, VALUE> | Generic table type |
Table Literal | { name: string, age: number } | Structured table |
Function | fun(param: string): boolean | Function signature |
Optional | string? | Same as string|nil |
Essential Annotations with Examples
Section titled “Essential Annotations with Examples”@type
- Variable Type Declarations
Section titled “@type - Variable Type Declarations”---@type stringlocal name = "John"
---@type number[]local scores = {95, 87, 92}
---@type { [string]: boolean }local settings = { sound = true, music = false }
---@type fun(username: string): booleanlocal validateUser
@param
- Function Parameters
Section titled “@param - Function Parameters”---@param username string The user's name---@param age? number Optional age parameter---@param scores number[] Array of scoresfunction createUser(username, age, scores) -- function bodyend
--- Union type parameter---@param id string | numberfunction findById(id) end
--- Optional parameter with ?---@param callback? fun() Optional callback functionfunction processData(callback) end
@return
- Function Return Values
Section titled “@return - Function Return Values”--- Simple return---@return booleanfunction isValid() return true end
--- Named return with description---@return boolean success If operation succeeded---@return string? error Error message if failedfunction riskyOperation() return false, "Something went wrong"end
--- Multiple returns---@return integer count, string... namesfunction getNames() return 3, "Alice", "Bob", "Charlie" end
@class
- Defining Custom Types
Section titled “@class - Defining Custom Types”---@class User---@field name string---@field email string---@field age? number---@field scores number[]
---@param user Userfunction processUser(user) print(user.name) -- Autocomplete works here!end
--- Class inheritance---@class Admin: User---@field permissions string[]
@alias
- Type Aliases and Enums
Section titled “@alias - Type Aliases and Enums”--- Simple type alias---@alias UserID integer
--- Union type alias---@alias Status "active" | "inactive" | "pending"
--- Enum with descriptions---@alias Color---| '"red"' # Primary color red---| '"green"' # Primary color green---| '"blue"' # Primary color blue
---@param favoriteColor Colorfunction setColor(favoriteColor) end
@enum
- Runtime Enums
Section titled “@enum - Runtime Enums”---@enum LogLevellocal LOG_LEVELS = { DEBUG = 1, INFO = 2, WARN = 3, ERROR = 4}
---@param level LogLevelfunction logMessage(level, message) end
logMessage(LOG_LEVELS.INFO, "System started") -- Type-safe!
Advanced Annotations
Section titled “Advanced Annotations”@generic
- Generic Types
Section titled “@generic - Generic Types”--- Generic function---@generic T---@param item T---@return Tfunction identity(item) return item end
--- Generic class---@class Container<T>---@field value T
---@type Container<string>local stringContainer = { value = "hello" }
@overload
- Function Overloading
Section titled “@overload - Function Overloading”---@param name string---@param age number---@return User---@overload fun(name: string): User---@overload fun(id: number): Userfunction createUser(name, age) end
-- All these calls are valid:local user1 = createUser("Alice", 30)local user2 = createUser("Bob")local user3 = createUser(123)
@async
- Asynchronous Functions
Section titled “@async - Asynchronous Functions”---@async---@param url string---@return string responsefunction fetchData(url) end
-- Language server will show "await" hintlocal data = fetchData("https://api.example.com/data")
@diagnostic
- Controlling Error Reporting
Section titled “@diagnostic - Controlling Error Reporting”--- Disable specific diagnostics---@diagnostic disable-next-line: unused-locallocal unusedVariable = 42
--- Enable spell checking in file---@diagnostic enable: spell-check
Practical Examples
Section titled “Practical Examples”API Client with Full Type Safety
Section titled “API Client with Full Type Safety”---@class ApiResponse---@field success boolean---@field data any---@field error? string
---@class User---@field id integer---@field name string---@field email string
---@async---@param endpoint string---@return ApiResponsefunction apiRequest(endpoint) end
---@param id integer---@return User?function getUser(id) ---@type ApiResponse local response = apiRequest("/users/" .. id)
if response.success then ---@cast response.data User return response.data end
return nilend
Game Entity System
Section titled “Game Entity System”---@alias EntityType "player" | "enemy" | "item" | "npc"
---@class Vector2---@field x number---@field y number
---@class Entity---@field id integer---@field type EntityType---@field position Vector2---@field health number---@field maxHealth number
---@class Player: Entity---@field username string---@field inventory Item[]
---@param entity Entity---@param damage number---@return boolean entityDiedfunction applyDamage(entity, damage) entity.health = entity.health - damage return entity.health <= 0end
Best Practices
Section titled “Best Practices”- Start with critical functions: Add annotations to your most important functions first
- Use descriptive names: Good parameter names help with autocomplete
- Leverage union types: Use
|
for values that can be multiple types - Mark optional parameters: Use
?
suffix for parameters that can benil
- Create type aliases: Use
@alias
for complex or frequently used types - Enable strict mode: Configure LuaLS for stricter type checking in production
Conclusion
Section titled “Conclusion”LuaLS type annotations transform Lua development from a purely dynamic experience to one with robust type safety and intelligent assistance. By adopting these annotations, you can:
- Catch type errors before runtime
- Improve code documentation and readability
- Enhance IDE autocompletion and navigation
- Facilitate better team collaboration
- Create more maintainable codebases
Start gradually introducing annotations to your existing codebase, and you’ll quickly appreciate the productivity gains and error prevention they provide.