Some annotations span multiple lines. Each line must start with ---@ or ---| :
---@alias HTTPMethod---| 'GET' # HTTP GET request---| 'POST' # HTTP POST request---| 'PUT' # HTTP PUT request---| 'DELETE' # HTTP DELETE request
---@class User---@field id number User ID---@field name string Username---@field email string Email address---@field role 'admin'|'user'|'guest' User role
The ---| prefix (three dashes, pipe, space) is used for enumeration values in @alias annotations.
Place annotations directly above the function definition:
---@param name string Username---@param age number User age---@return table User objectfunction createUser(name, age) return {name = name, age = age}end
Define the class structure, then the implementation:
---@class Animal---@field name string Animal name---@field species string Species---@field age number Age in yearslocal Animal = {}---@param name string---@param species string---@return Animalfunction Animal.new(name, species) return setmetatable({ name = name, species = species, age = 0 }, {__index = Animal})end
Some annotation parameters are required, others are optional:
-- @type requires only the type---@type string-- @param requires name and type, description is optional---@param name string---@param age number User age in years-- @class requires name, parent classes are optional---@class User---@class Admin : User---@class SuperAdmin : Admin, Auditable
---@generic T---@param items T[]---@param predicate fun(item: T): boolean---@return T[]function filter(items, predicate) local result = {} for _, item in ipairs(items) do if predicate(item) then table.insert(result, item) end end return resultend
---@class Calculator---@field value number Current value---@field history number[] Calculation historylocal Calculator = {}---@param initial number Starting value---@return Calculatorfunction Calculator.new(initial) return setmetatable({ value = initial, history = {initial} }, {__index = Calculator})end---@param x number Number to add---@return Calculator self For method chainingfunction Calculator:add(x) self.value = self.value + x table.insert(self.history, self.value) return selfend
--- Vector class for 2D coordinates---@class Vector---@field x number X coordinate---@field y number Y coordinatelocal Vector = {}--- Create a new vector---@param x number X coordinate---@param y number Y coordinate---@return Vector A new vector instancefunction Vector.new(x, y) return setmetatable({x = x, y = y}, {__index = Vector})end--- Calculate the magnitude of the vector---@return number The magnitudefunction Vector:magnitude() return math.sqrt(self.x^2 + self.y^2)end
You can mix both formats in the same project, but maintaining consistency improves readability.
Choose a style and stick to it throughout your project:
-- Good: Consistent formatting---@param name string---@param age number---@return User-- Avoid: Inconsistent spacing---@param name string---@param age number---@return User
-- Public API - fully documented---@class Database---@field host string---@field port number---@param config {host: string, port: number}---@return Databasefunction Database.new(config) -- Implementationend-- Private helper - can be less formallocal function parseConnectionString(str) -- Implementationend
---@param options {timeout: number, retries: number, backoff: boolean} Configuration options for the request. Timeout in seconds, retries is the max number of attempts, backoff enables exponential backofffunction httpRequest(url, options)end
-- Good: Grouped by purpose---@class User---@field id number---@field name string---@field email string---@field createdAt number---@field updatedAt number-- Less organized: Mixed ordering---@class User---@field name string---@field id number---@field updatedAt number---@field email string---@field createdAt number