This quick tutorial assumes you are already familiar with basic typings in Luau. While some behaviorisms of the new typesystem may be different, the underlying concepts are all the same.
Luau’s new typesolver can be enabled in studio via the "New Luau type solver"
beta feature. For the intents of this tutorial, I will be using the --!strict
mode.
The new typesolver provides what are called type functions, which allow for generic evaluation of their argument types. These functions are naturally invoked when using their correlated operations, but they can also be used in type annotations.
Here is the list of all the current type functions and their correlated operations (as of the time of writing):
add<a, b> a + b
sub<a, b> a - b
mul<a, b> a * b
div<a, b> a / b
idiv<a, b> a // b
mod<a, b> a % b
pow<a, b> a ^ b
concat<a, b> a .. b
eq<a, b> a == b
lt<a, b> a < b
le<a, b> a <= b
len<a> #a
unm<a> -a
index<a, b> a[b]
rawget<a, b> rawget(a, b)
keyof<a> Union of a Record's Keys
rawkeyof<a> Same without Metatables
When a type with a metatable is used with the type function, it will return the correct type its metamethods expect (otherwise it just returns never
).
type Object = typeof(
setmetatable(
{},
{} :: {
-- Adding two Objects will return a string
__add: (self: Object, Other: Object) -> string
}
)
)
type Return = add<Object, Object> -- Evaluates as string!
The index
function also works on Roblox userdata, so you can actually get the types of properties from Instances and such.
type Color = index<BasePart, "Color"> -- Evaluates as Color3!
The last oddballs, keyof
and rawkeyof
, are used to get the union of a record type’s keys. This is useful when writing custom wrappers.
type Record = {
Time: number,
Name: string,
Position: Vector3,
Model: Model
}
type RecordKeys = keyof<Record> -- "Time" | "Name" | "Position" | "Model"
User-defined type functions are also on the roadmap, so hopefully those come soon. With those, basically anything in the type system will be possible!