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:
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:
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:
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:
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:
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:
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:
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:
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: