Source: Luau.org · MIT · View source Imported 2026-10-03. Formatting adapted for this site.
Generics and Polymorphism
The type inference engine was built from the ground up to recognize generics. A generic is simply a type parameter in which another type could be slotted in. It's extremely useful because it allows the type inference engine to remember what the type actually is, unlike any.
type Pair<T> = {first: T, second: T }
-- generics can also have defaults!
type PairWithDefault<T = string> = Pair<T>
local strings: Pair<string> = { first="Hello", second="World" }
local numbers: Pair<number> = { first=1, second=2 }
-- can just treat PairWithDefault as a type that doesnt have generics because it has all of its generics assigned a default!
local more_strings: PairWithDefault = { first = "meow", second = "mrrp" } Generic functions
As well as generic type aliases like Pair<T>, Luau supports generic functions. These are functions that, as well as their regular data parameters, take type parameters. For example, a function which reverses an array is:
function reverse(a)
local result = {}
for i = #a, 1, -1 do
table.insert(result, a[i])
end
return result
end The type of this function is that it can reverse an array, and return an array of the same type. Luau can infer this type, but if you want to be explicit, you can declare the type parameter T, for example:
function reverse<T>(a: {T}): {T}
local result: {T} = {}
for i = #a, 1, -1 do
table.insert(result, a[i])
end
return result
end When a generic function is called, Luau infers type arguments, for example
--!file main.luau
local reverse = require("./reverse")
local x: {number} = reverse({1, 2, 3})
local y: {string} = reverse({"a", "b", "c"})
--!file reverse.luau
function reverse<T>(a: {T}): {T}
local result: {T} = {}
for i = #a, 1, -1 do
table.insert(result, a[i])
end
return result
end
return reverse Generic types are used for built-in functions as well as user functions, for example the type of two-argument table.insert is:
<T>({T}, T) -> () Note: Functions don't support having defaults assigned to generics, meaning the following is invalid
function meow<T = string>(mrrp: T)
print(mrrp .. " :3")
end Generic type instantiation
By default, Luau will infer the type arguments when calling a generic function. You can also provide them explicitly using the syntax func<<Type>>(...). This is called generic type instantiation or just type instantiation. For example,
local function identity<T>(x: T): T
return x
end
local a = identity<<number>>(42) -- T is explicitly number
local b = identity<<string>>("hi") -- T is explicitly string
local c = identity<<"hi">>("hi") -- T is explicitly the singleton type "hi" Explicit instantiation is useful when inference would be ambiguous or when you want to constrain the inferred type to a supertype:
local function makeList<T>(): {T}
return {}
end
-- Without explicit instantiation, Luau would not be able to infer `T` from the arguments alone
local nums = makeList<<number>>() -- {number}
local strs = makeList<<string>>() -- {string} You can also instantiate multiple type parameters at once by separating them with commas:
local function swap<A, B>(a: A, b: B): (B, A)
return b, a
end
local x, y = swap<<number, string>>(1, "hello")
-- x: string, y: number