Back to Luau

An introduction to Luau types

types.md

latest7.1 KB
Original Source

An introduction to Luau types

Luau supports a gradual type system through the use of type annotations and type inference. These types are used to provide warnings, errors, and suggestions for our developers. Type checking helps you find bugs early - while you’re writing code - rather than discovering when your program crashes at runtime.

Type inference modes

Section titled “Type inference modes”

Luau offers three different modes that control how strictly it checks your types. You can set the mode by adding one of the following to the top of your file:

  • --!nocheck,
  • --!nonstrict (default), and
  • --!strict
--!nocheck

Section titled “--!nocheck”

nocheck mode completely disables the type inference engine for the file.

With this mode enabled, we don’t provide any feedback on the types, so scripts with errors (like following example that tries to add a string and a number) will not raise a typecheck error, even though the program errors when executed.

Try pressing the Check and Run buttons to try out this snippet:

Embedded content

If, instead, you want to catch these kinds of errors before running your code, you can enable type checking with the --!nonstrict or --!strict modes. Both of these modes analyze your types and provide helpful feedback, but they differ slightly in how strictly they enforce type safety.

--!nonstrict

Section titled “--!nonstrict”

In nonstrict mode, the type checker is more forgiving: if we can’t figure out what type something is early on, we infer the type could be anything (the any type) and let you proceed without errors.

This means that if we define a variable without initializing it or specifying its type:

Embedded content

The type checker can’t tell what type foo should be when it’s first declared, so in nonstrict mode it infers any - allowing the addition to proceed without warnings, even though it will error at runtime.

--!strict

Section titled “--!strict”

In strict mode, Luau is smarter about tracking types across statements. Given the previous example now in strict mode:

Embedded content

We see an error! The type checker sees foo = 1 on line 4 and infers that foo must be a number. Then, when you try to add "hello " and foo, strict mode catches our error of trying to add a string and a number, which isn’t allowed. (tip: hover over the erroneous lines to see the error message!)

Structural type system

Section titled “Structural type system”

Luau’s type system is structural by default, which is to say that we inspect the shape of two tables to see if they are similar enough. This was chosen because Lua 5.1 is inherently structural.

Take, for example, these two tables A and B:

Embedded content

Type annotations

Section titled “Type annotations”

While Luau’s type system can infer many types, you can also annotate types using a colon (:) followed by the type:

Embedded content

Type casts

Section titled “Type casts”

Sometimes, you might want to specify the type of an expression when the automatically inferred type is too generic. In these cases, you can use a type cast with the :: operator to tell Luau what type something should be.

For example, consider the following table constructor where the intent is to store a table of names:

Embedded content

Inserting a number into names ought to cause a type error, but doesn’t.

In order to specify the type of the names table, we can use a typecast:

Embedded content

Now, inserting a number raises a type error, informing the user that there is an invalid 'number' to 'string' conversion.

Type cast rules

Section titled “Type cast rules”

Type casts themselves are also type checked to ensure that one of the conversion operands is the subtype of the other or any:

Embedded content

This prevents unsafe casts between incompatible types.

Type casts with multiple return values

Section titled “Type casts with multiple return values”

When typecasting a variadic or the result of a function with multiple returns, only the first value will be preserved, and the rest discarded:

Embedded content