Skip to main content
Force type conversion for variables, used for type narrowing or extension in union types.

Syntax

---@cast <variable_name> [+|-]<type>[, [+|-]<type>...]
  • No prefix: Replace the variable’s type entirely
  • + prefix: Add a type to the union
  • - prefix: Remove a type from the union

Examples

Type Narrowing

Confirm a variable’s type after runtime checks:
---@param value any
function processValue(value)
    if type(value) == "string" then
        ---@cast value string
        print("String length:", #value)  -- value is now confirmed as string type
    end

    if type(value) == "table" and value.id then
        ---@cast value {id: number, name?: string}
        print("ID:", value.id)           -- value now has id field
    end
end

Adding Types to Unions

---@type string | number
local mixedValue = getValue()

if needsBoolean() then
    ---@cast mixedValue +boolean  -- Add boolean type
    mixedValue = true
end
-- mixedValue is now: string | number | boolean

Removing Types from Unions

---@type string | number | nil
local maybeValue = getMaybeValue()

if maybeValue then
    ---@cast maybeValue -nil      -- Remove nil type
    print("Value:", maybeValue)   -- maybeValue is now string | number
end

Complex Type Casting

Cast to specific structures:
---@type table
local data = parseJSON(jsonString)

-- Cast to specific structure
---@cast data {users: {id: number, name: string}[]}
for _, user in ipairs(data.users) do
    print("User:", user.name, "ID:", user.id)
end

Type Confirmation in Guards

---@param input string | number | boolean
function handleInput(input)
    if type(input) == "string" and input:match("^%d+$") then
        ---@cast input string  -- Confirm it's string type
        local num = tonumber(input)
        ---@cast num number    -- tonumber result confirmed as number
        print("Number:", num)
    end
end

Multiple Type Operations

Add or remove multiple types at once:
-- Add multiple types
---@type string
local value = "initial"

---@cast value +number, +boolean  -- Add number and boolean types
-- value is now: string | number | boolean

-- Remove multiple types
---@type string | number | boolean | nil
local multiValue = getMultiValue()

---@cast multiValue -boolean, -nil  -- Remove boolean and nil types
-- multiValue is now: string | number

Common Use Cases

Narrowing After Validation

---@param data any
function processData(data)
    if validate(data) then
        ---@cast data {id: number, name: string, email: string}
        -- Now safely access typed fields
        local userId = data.id
        local userName = data.name
    end
end

Working with Optional Values

---@type string?
local optionalValue = getOptional()

if optionalValue ~= nil then
    ---@cast optionalValue string  -- Remove nil from type
    -- Safe to use as string now
    print(optionalValue:upper())
end
Type casts do not perform runtime type conversion. They only inform the analyzer about the type. Always ensure your runtime checks match your casts.
Use @cast after validation logic to help the analyzer understand type narrowing from your runtime checks.

Features

Type Narrowing

Narrow types after runtime validation

Type Extension

Add types to union types

Union Operations

Add or remove types from unions

Structure Casting

Cast to specific table structures

Build docs developers (and LLMs) love