Back to Luau

Primitives and Simple Types

types-basic-types.md

latest10.5 KB
Original Source

Primitives and Simple Types

Builtin types

Section titled “Builtin types”

The Luau VM supports 10 primitive types:

  1. nil
  2. string
  3. number
  4. boolean
  5. table
  6. function
  7. thread
  8. userdata
  9. vector
  10. buffer

Most of these can be specified by their name and written directly in type annotations:

Embedded content

Some types have special syntax:

  • table and function are not represented by name, but have their dedicated syntax as covered in this syntax document
  • userdata is represented by concrete types, and
  • vector is not representable by name at all

The type checker also provides the builtin types unknown, never, and any.

Embedded content

Special behavior with nil

Section titled “Special behavior with nil”

There’s a special case where we intentionally avoid inferring nil for local variables. This allows you to declare variables first and assign values to them later — if we inferred nil, you wouldn’t be able to assign other types to these variables.

Embedded content

unknown type

Section titled “unknown type”

unknown is also said to be the top type, that is it’s a union of all types.

Embedded content

Unlike any, unknown will not allow itself to be used as a different type!

Embedded content

In order to turn a variable of type unknown into a different type, you must apply type refinements on that variable.

Embedded content

never type

Section titled “never type”

never is also said to be the bottom type, meaning there doesn’t exist a value that inhabits the type never. In fact, it is the dual of unknown. never is useful in many scenarios, and one such use case is when type refinements proves it impossible:

Embedded content

any type

Section titled “any type”

any is just like unknown, except that it allows itself to be used as an arbitrary type without further checks or annotations. Essentially, it’s an opt-out from the type system entirely.

Embedded content

Function types

Section titled “Function types”

Let’s start with something simple.

Embedded content

In strict mode, the inferred type of this function f is <A>(A) -> A (take a look at generics), whereas in nonstrict we infer (any) -> any. We know this is true because f can take anything and then return that. If we used x with another concrete type, then we would end up inferring that.

Similarly, we can infer the types of the parameters with ease. By passing a parameter into anything that also has a type, we are saying “this and that has the same type.”

Embedded content

Variadic types

Section titled “Variadic types”

Luau permits assigning a type to the ... variadic symbol like any other parameter:

Embedded content

f accepts any number of number values.

In type annotations, this is written as ...T:

Embedded content

Type packs

Section titled “Type packs”

Multiple function return values as well as the function variadic parameter use a type pack to represent a list of types.

When a type alias is defined, generic type pack parameters can be used after the type parameters:

Embedded content

Keep in mind that ...T is a variadic type pack (many elements of the same type T), while U... is a generic type pack that can contain zero or more types and they don’t have to be the same.

It is also possible for a generic function to reference a generic type pack from the generics list:

Embedded content

Generic types with type packs can be instantiated by providing a type pack:

Embedded content

There are also other ways to instantiate types with generic type pack parameters:

Embedded content

Trailing type pack argument can also be provided without parentheses by specifying variadic type arguments:

Embedded content

Type pack parameters are not limited to a single one, as many as required can be specified:

Embedded content

Singleton types (aka literal types)

Section titled “Singleton types (aka literal types)”

Luau’s type system also supports singleton types, which means it’s a type that represents one single value at runtime. At this time, both string and booleans are representable in types.

We do not currently support numbers as types. For now, this is intentional.

Embedded content

This happens all the time, especially through type refinements and is also incredibly useful when you want to enforce program invariants in the type system! See tagged unions for more information.