A maybe-helpful summary of the Luau docs
Modes must be defined at the top of the file.
--!nonstrict
(default): Inferany
for types early.--!strict
: Infers types based on analysis of your script (initalized values, function params & return values, etc).--!nocheck
: Typechecker is not run at all.
Strict mode will infer types of variables declared but not immediately defined, non-strict will infer any
, ie
local foo = 1 -- Strict: number; nonstrict: number
local bar
bar = 1 -- Strict: number; nonstrict: any
local function f(x) return x end -- Strict: <A>(A) -> A; nonstrict: (any) -> any
Strict mode will emit an error for global variables, use local variables instead
any
essentially disables typechecking, literally "anything is ok here!"
nil
is never inferred since that isn't useful
Types will cascade, ie
local function greetingsHelper(name: string)
return "Hello, " .. name
end
local function greetings(name)
return greetingsHelper(name)
end
print(greetings("Alexander")) -- ok
print(greetings({name = "Alexander"})) -- not ok
Define a type by annotating a variable or function with the :
symbol, ie:
function foo(x: number, y: string): boolean
local k: string = y:rep(x)
return k == "a"
end
Or create a type alias by using the type
keyword, ie.
type Foo = any
type Point = { x: number, y: number }
type Array<T> = { [number]: T }
type Something = typeof(string.gmatch("", "\d"))
Type aliases are local to their own file unless the export
keyword is used, ie
type Foo = any
A619
export Foo
export type Point = {x: number, y: number}
Exported types can be used in another module by prefexing its name with the require alias, ie
local M = require(Other.Module)
local a: M.Point = {x=5, y=6}
Override types with ::
, ie: local k = (y :: string):rep(x)
Built-in types are any
, nil
, boolean
, number
, string
, thread
Optional parameters can be denotated by ?
, ie number?
Generic types can be defined with <T>
ie type Pair<T> = {first: T, second: T}
Variadic args can be typed like any other argument, ie local function f(...: number)
Intersection (conforms to both): A & B, ie ((number) -> string) & ((boolean) -> string)
Union (either-or): A | B, ie (number | boolean) -> string
Checking a type inherently refines it, ie
local stringOrNumber: string | number = "foo"
if type(x) == "string" then
local onlyString: string = stringOrNumber -- ok
local onlyNumber: number = stringOrNumber -- not ok
end
local onlyString: string = stringOrNumber -- not ok
local onlyNumber: number = stringOrNumber -- not ok
local maybeString: string? = nil
if maybeString then
local onlyString: string = maybeString -- ok
end
local stringOrNumber2: string | number = "foo"
assert(type(stringOrNumber2) == "string")
local onlyString: string = stringOrNumber2 -- ok
local onlyNumber: number = stringOrNumber2 -- not ok
Function types are defined with () ->
, ie. local foo: (number, string) -> boolean
Functions which return 0 or more than 1 values must be wrapped with ()
, ie:
local no_returns: (number, string) -> ()
local returns_boolean_and_string: (number, string) -> (boolean, string)
A function's variable names may optionally be specified in the type, ie:
local callback: (errorCode: number, errorText: string) -> ()
Generic functions will be defined as <T>({T}, T) -> ()
but is not available at time of writing.
Tables are unsealed
, sealed
, or generic
.
unsealed
tables can have properties added and can have their values changedsealed
tables CANNOT have properties added but can have their values changedgeneric
tables have some interface defined, but not completely
local function vec2(x, y)
local t = {} -- table is unsealed
t.x = x
t.y = y
return t
end
local v2 = vec2(1, 2) -- table exits its original scope and is now sealed
v2.z = 3 -- not ok
local t = {x = 1} -- table is sealed since it had things defined in it
t.y = 2 -- not ok
local function f(t)
return t.x + t.y -- table is generic since we cannot know that
-- there aren't more properties than x and y
end
f({x = 1, y = 2}) -- ok
f({x = 1, y = 2, z = 3}) -- ok
f({x = 1}) -- not ok
Table types are specified using the same syntax as creating a table, but with :
, ie
local array: { [number] : string }
local arrayShorthand: {string}
local object: { x: number, y: string }
local arrayOfObjects: {[number] : { x: number, y: string}}
Any valid Lua 5.1 code is valid Luau... (See: Lua 5.1 Reference Manual)
...unless there's sandboxing concerns (See: Luau Compatibility, Lua 5.1)
break
andcontinue
keywords exist now- Compound assignments (
+=
,-=
, etc) exist now
All roblox types are known to the typechecker by name.
- yieldable pcall/xpcall
- hex and \z escapes in strings
- arguments for function called through xpcall
- optional base in math.log
- frontier patterns
- %g in patterns
- \0 in patterns
- bit32 library
- string.gsub is stricter about using % on special characters only
- \u escapes in strings
- basic utf-8 support
- functions for packing and unpacking values (string.pack/unpack/packsize)
- new function table.move
- collectgarbage("count") now returns only one result
- coroutine.isyieldable
- new implementation for math.random
- The function print calls __tostring instead of tostring to format its arguments.