Types

Built-in types

class nil

The type nil has one single value, nil, whose main property is to be different from any other value; it usually represents the absence of a useful value.

class boolean

The type boolean has two values, false and true. Both nil and false make a condition false; any other value makes it true.

class number

Lua uses two internal representations for numbers: integer and float. It has explicit rules about when each representation is used, but it also converts between them automatically as needed.

EmmyLua, on the other hand, allows explicitly annotating which representation is expected. The number type can contain both integer and float values. The integer is a sub-type of number, and only allows integer values.

See also

Lua’s manual on value types.

class integer

The type integer is a sub-type of number that only allows numbers with integer representation.

class userdata

The type userdata is provided to allow arbitrary C data to be stored in Lua variables. A userdata value represents a block of raw memory. There are two kinds of userdata: userdata, which is an object with a block of memory managed by Lua, and lightuserdata, which is simply a C pointer value.

See also

Lua’s manual on value types.

class lightuserdata

The type lightuserdata is a sub-type of userdata that only allows values with light userdata representation.

class thread

The type thread represents independent threads of execution and it is used to implement coroutines. Lua threads are not related to operating-system threads. Lua supports coroutines on all systems, even those that do not support threads natively.

class table<K, V>

The type table implements associative arrays, that is, arrays that can have as indices not only numbers, but any Lua value except nil and NaN. (Not a Number is a special floating-point value used by the IEEE 754 standard to represent undefined or unrepresentable numerical results, such as 0/0.)

While lua allows mixing types of keys and values in a table, EmmyLua has an option to specify their exact types. Simply using type table creates a heterogeneous table (equivalent to table<unknown, unknown>), while explicitly providing key and value types creates a homogeneous table:

 --- @type table
 local tableWithArbitraryData = {}

 --- @type table<string, integer>
 local tableWithStringKeysAndIntValues = {}

You can also specify the exact shape of a table by using a table literal:

 --- @type { username: string, age: integer }
 local User = { ... }

See also

Lua’s manual on value types.

class any

The type any is compatible with any other type. That is, all types can be converted to and from any.

This type is a way to bypass type checking system and explicitly tell EmmyLua that you know what you’re doing.

Tip

Prefer using unknown instead of any to signal the need to be careful and explicitly check value’s contents.

class unknown

The type unknown is similar to any, but signifies a different intent.

While any is a way to say “I know what I’m doing”, unknown is a way to say “better check this value before using it”.

class void

Void is an alias for nil used in some code bases. Prefer using nil instead.

class self

A special type used with class methods. It can be thought of as a generic parameter that matches type of the function’s implicit argument self. That is, when a function is called via colon notation (i.e. table:method()), self is replaced with the type of expression before the colon.

This is especially handy when dealing with inheritance. Consider the following example:

 --- @class Base
 local Base = {}

 --- @return self
 function Base:new()
     return setmetatable({}, { __index=self })
 end

 --- @class Child: Base
 local Child = setmetatable({}, { __index=Base })

 local child = Child:new()

Here, EmmyLua infers type of child to be Child, even though new was defined in its base class. This is because new uses self as its return type.

Metaprogramming library

alias std.NotNull<T> = sub<T, nil>

A type for assert function. Given a nullable type T expands to a non-nullable version of T.

For example, if T is string?, then std.NotNull<T> will be string.

alias std.Unpack<T, Start, End> = unknown

A type for table.unpack function. Given a type T and optional literal types Start and End, expands to the type of expression table.unpack(t, start, end).

Example:

 --- @generic T
 --- @param list T
 --- @return std.Unpack<T>
 function customUnpack(list) end

 local a, b, c = customUnpack({1, 2, 3})

Here, a, b and c will be inferred as integers.

alias std.RawGet<T, K> = unknown

A type for rawget function. Given a type T and a literal type K, expands to the type of expression rawget(t, k).

Example:

 --- @class Example
 --- @field value integer

 --- @type std.RawGet<Example, "value">
 local value

Here, std.RawGet<Example, "value"> will be expanded to integer.

alias std.ConstTpl<T> = unknown

A wrapper for matching literal types in generics.

By default, generics variables that match literal values decay to values’ base types:

 --- @generic T
 --- @param x T
 --- @return T
 local function id(x)
     return x
 end

 local original --- @type "literal"

 local value = id(original)

Here, type of value will be inferred as string even though original’s type was "literal".

We can prevent this behavior by wrapping generic pattern for T into std.ConstTpl<T>:

 --- @generic T
 --- @param x std.ConstTpl<T>
 --- @return T
 local function id(x)
     return x
 end

 local original --- @type "literal"

 local value = id(original)

Here, type of value will be inferred as "literal".