Skip to content

All Annotations

Quick reference for every annotation wowlua-ls supports. For detailed usage and examples, see the guide.

Type annotations

AnnotationDescriptionGuide
@param name typeParameter type. name? for optional.Basic Annotations
@return type [name]Return type. Use multiple lines or one comma-separated line (@return A, B) for multi-return.Basic Annotations
@return (A, B) | (C, D)Tuple-union return with correlated narrowing.Multi-Return
@return ...TVariadic return — fills remaining positions with T.Multi-Return
@type typeVariable type annotation.Basic Annotations
@as typeInline expression type assertion (--[[@as T]]).Basic Annotations
@cast var [+|-]typeChange variable type: replace, add (+), remove (-).Basic Annotations

Class and type annotations

AnnotationDescriptionGuide
@class NameDefine a named class type.Classes
@class Name : ParentClass with inheritance.Classes
@class Name : A, BMultiple parent classes (comma-separated).Classes
@class Name : A & BMultiple parent classes (intersection syntax).Classes
@class Name : table<K, V>Class with dictionary key/value types.Classes
@class (partial) NameAccepted for compatibility (currently ignored).Classes
@class Name<T>Parameterized class.Generics
@class Name<T: Constraint>Parameterized class with type constraint.Generics
@enum NameEnum type — bidirectionally compatible with number or string (inferred from values).Classes
@enum (key) NameKey-based enum — creates a string enum from table keys instead of values.Classes
@event TypeName "EVENT_NAME"Declare an event with typed payload (hover + handler param narrowing).Events
@event TypeName + ---|Batch event declarations with inline params.Events
@field name typeClass field declaration.Classes
@field [K] VBracket-index field.Generics
@field private name typePrivate field.Classes
@field protected name typeProtected field.Classes
@correlated f1, f2, ...Fields or locals that are always nil/non-nil together.Nil Safety

Generic annotations

AnnotationDescriptionGuide
@generic TGeneric type parameter on a function.Generics
@generic T: ClassConstrained generic.Generics
@generic T, K: keyof TKey-constrained generic — K must be a field name of T.Generics
@generic K: keyof selfMethod receiver key constraint — K must be a field name of the call's receiver.Generics
@generic T, ...MVariadic generic — collects excess arguments into an intersection.Generics
@requires T: ConstraintMethod is only callable when the receiver's class type parameter T satisfies the constraint.Generics
@param name `T`Resolve string argument as a class name.Generics
@overload fun(...)Function overload signature.Generics

Factory and builder annotations

AnnotationDescriptionGuide
@defclass TClass factory function.Classes
@defclass T : PClass factory with parent parameter.Classes
@builds-field idx typeBuilder method adds a field.Builder Pattern
@return builtReturn the accumulated built type.Builder Pattern
@return built : ParentBuilt type with parent class.Builder Pattern
@built-name idxName the built type from a string argument.Builder Pattern
@built-extendsBuilt type inherits from receiver's built type.Builder Pattern
@return selfMethod returns the receiver (for chaining).Builder Pattern
@return self<X>Method returns the receiver re-parameterized with type argument X.Builder Pattern

Narrowing and guard annotations

AnnotationDescriptionGuide
@type-narrows target classType guard function (index-based).Type Guards
@type-narrows ClassNameType guard method (narrows self).Type Guards
@returns-class-nameMethod whose string return value names the receiver's class; recv:m() == "Class" narrows recv to Class.Type Guards
@narrows-arg NBare call narrows the Nth argument's type to the return type.Type Guards
@flavor-narrows flavorFlavor guard function or boolean.Flavor Filtering

Metadata annotations

AnnotationDescription
@alias Name typeType alias. Supports parameters: @alias Name<K,V> V[], including constrained parameters: @alias Box<T: Frame> { value: T }. Use @alias (opaque) Name type for a nominally distinct type (see below).
@deprecatedMark as deprecated.
@nodiscardWarn if return value is ignored.
@metaDeclaration-only file. Suppresses runtime/behavior diagnostics, but annotation-integrity checks still fire — a malformed, misplaced, or dangling annotation is a real error even in a stub. This covers undefined type/class references (undefined-doc-name, undefined-doc-class), malformed annotations, @field/@param not attached to a @class/function (doc-field-no-class, doc-func-no-function), invalid @diagnostic codes, and nil table-key types.
@diagnostic disable:codeSuppress a diagnostic inline.
@see symbolCross-reference shown in hover.
@constructorMark a method as the class constructor.
@accessor name [visibility]Set visibility for methods defined through a sub-table accessor. Guide
@creates-global NCalling this function with a string literal at param N creates a named global. The global's type is taken from the call's return type.
@generates-events N [Field]Calling this method with an array table at param N synthesizes an enum-like Field table (default Event) on the receiver class, one member per array entry.
@callback-event-arg NMarks a callback-registry consumer method (RegisterCallback/TriggerEvent/…) whose argument N is an event name — enables event-name completion and the unknown-callback-event diagnostic.

@creates-global N

Some functions create a global as a side effect of being called — for example World of Warcraft's CreateFrame("Frame", "MyFrame") defines _G.MyFrame. Mark such a function so that reading the created name in another file does not produce a false undefined-global diagnostic:

  • N (1-based) is the parameter whose string-literal argument names the created global.

The created global's type is the call's actual return type — you don't specify it. This means a call carrying a template/mixin gets the full type: a CreateFrame("Frame", "MyFrame", parent, "MyTemplate") global is typed Frame & MyTemplate, not a bare Frame.

lua
---@param frameType FrameType
---@param name? string
---@return T frame
---@creates-global 2   -- param 2 names the global; its type is the return type
function CreateFrame(frameType, name, ...) end

---@param name string
---@return Font
---@creates-global 1   -- param 1 names the global; it is a Font (from @return)
function CreateFont(name) end

Only string-literal arguments are detected; dynamic names (e.g. CreateFrame("Frame", varName)) are not registered.

INFO

Currently, only functions defined in API stubs are detected as @creates-global sources. The annotation is parsed on workspace-defined functions but their calls are not yet scanned for created globals.

@generates-events N [Field]

Some methods populate an enum-like table on their receiver as a side effect of being called. World of Warcraft's CallbackRegistryMixin:GenerateCallbackEvents({ "OnFoo", ... }) builds self.Event = { OnFoo = "OnFoo", ... }, which addons later reference as Mixin.Event.OnFoo. Mark such a method so those accesses resolve instead of producing a false undefined-field:

  • N (1-based) is the call argument that holds the array table of event names.
  • Field (optional, default Event) is the table field synthesized on the receiver class.
lua
---@generates-events 1 Event   -- arg 1 is the event array; build `self.Event`
---@param events string[]
function CallbackRegistryMixin:GenerateCallbackEvents(events) end

The receiver must be a single-name class (e.g. ScrollBoxListMixin, not a dotted chain). Each array entry contributes one string member: string literals use their value, and field references (SomeEvents.OnFoo) use the leaf name OnFoo, matching the value-equals-name convention. Accessing an event that isn't in the array still resolves leniently — the synthesized table is not closed.

lua
ScrollBoxListMixin:GenerateCallbackEvents({
    BaseScrollBoxEvents.OnScroll,        -- → ScrollBoxListMixin.Event.OnScroll
    "OnDataProviderReassigned",          -- → ScrollBoxListMixin.Event.OnDataProviderReassigned
})

local e = ScrollBoxListMixin.Event.OnDataProviderReassigned  -- string, no diagnostic

@callback-event-arg N

Addons that mix in CallbackRegistryMixin usually register and fire events by string-literal name rather than through the .Event table:

lua
addonTable.CallbackRegistry:RegisterCallback("SettingChanged", handler)
addonTable.CallbackRegistry:TriggerEvent("SettingChanged", value)

@callback-event-arg N marks a consumer method whose N-th argument is such an event name. Combined with the registry's declared events (from GenerateCallbackEvents, including an addonTable.Constants.Events-style string array resolved across files), the language server then:

  • completes the registered event names inside the string argument, and
  • flags an unregistered name with unknown-callback-event (off by default).
lua
---@callback-event-arg 1   -- arg 1 is the event name
---@param event string
function CallbackRegistryMixin:RegisterCallback(event, func, owner, ...) end

The registry receiver is matched by name (a global, a class, or an addonTable.X namespace field — the addon-namespace alias is normalized so the declaration and the call sites agree across files, and scoped by addon so separate addons in one workspace don't share an event set). When a registry's event set can't be fully determined, validation is suppressed for it so no false positives are reported.

Opaque aliases

@alias (opaque) creates a nominally distinct type that prevents accidental mixing of values that share the same underlying type:

lua
---@alias (opaque) PlayerID number
---@alias (opaque) ItemID number

---@param id PlayerID
local function lookupPlayer(id) end

lookupPlayer(42)            -- OK: number literal matches inner type
lookupPlayer(getItemID())   -- ERROR: ItemID is not PlayerID

Rules:

  • Literal values and base-type values are accepted where an opaque alias is expected (e.g. 42 passes as PlayerID)
  • An opaque alias flows out to its base type freely (e.g. PlayerID passes where number is expected)
  • Different opaque aliases with the same inner type are not interchangeable (ItemID cannot be used as PlayerID)
  • Arithmetic and other operators unwrap to the inner type; results decay to the base type (PlayerID + 1 produces number)
  • Hover displays the alias name, not the inner type

Works with any inner type including string literal unions:

lua
---@alias (opaque) Answer "YES"|"NO"
---@alias (opaque) Toggle "YES"|"NO"

---@param a Answer
local function process(a) end

process("YES")          -- OK
process(getToggle())    -- ERROR: Toggle is not Answer

Type syntax

SyntaxMeaning
string, number, boolean, nil, anyPrimitives
integerInteger subtype of number
tableAny table
functionAny function
A | BUnion
A & BIntersection
T[]Array
T[K]Indexed access — field type of K on T
[T1, T2]Tuple — fixed-shape table ({ [1]: T1, [2]: T2 })
T?Optional (T | nil)
?TOptional, prefix form — same as T?
T!Non-nil / lateinit
table<K, V>Map type
fun(a: T): RFunction type
{f: T, g?: U}Anonymous table shape
"literal"String literal type
true, falseBoolean literal types
0, -1, 0xFFNumber literal types (e.g. a | (0, nil, nil) tuple-union case)
params<F>Function parameter projection (vararg only)
params<EventType>Event payload projection — types varargs per-event
returns<F>Function return type projection
expression<C>Expression string type — fields of class C become variables
expression<C, R>Expression string with return type constraint R
expression<C, R> (R is @generic)Result type R inferred from the expression and propagated to the return
expression<C & F>Expression string with additional functions/fields from F
expression<C & F, R>Expression with extra environment and return constraint