Guard
A runtime type checker with support for luau types.
Guard is very similar to and takes inspiration from Osyris' t
module. The primary difference between the two is that Guard is designed to be used with luau, and as such supports luau types.
Design
Every Guard function either returns a check, or is a check.
What is a Check?
A check is a function that takes a value of unknown type and returns a value of known type or errors. You can combine checks to create more complex checks.
Example Usage
local NumberListCheck = Guard.List(Guard.Number)
local NumberList = NumberListCheck({1, 2, 3}) -- Passes and returns {1, 2, 3}
local StringList = NumberListCheck({"a", "b", "c"}) -- Fails and errors
local NumberListCheck = Guard.List(Guard.Number)
local NumberList = NumberListCheck({1, 2, 3}) -- Passes and returns {1, 2, 3}
local StringList = NumberListCheck({"a", "b", "c"}) -- Fails and errors
If you wish to check a value without erroring, you can use Check
:
local NumberListCheck = Guard.Check(Guard.List(Guard.Number))
local Pass, NumberList = NumberListCheck({1, 2, 3}) -- Passes and returns true, {1, 2, 3}
local Pass, StringList = NumberListCheck({"a", "b", "c"}) -- Fails and returns false, nil
local NumberListCheck = Guard.Check(Guard.List(Guard.Number))
local Pass, NumberList = NumberListCheck({1, 2, 3}) -- Passes and returns true, {1, 2, 3}
local Pass, StringList = NumberListCheck({"a", "b", "c"}) -- Fails and returns false, nil
How to Check Interfaces
Due to Luau limitations Guard cannot check interfaces directly. Instead you can define custom check functions that check the interface:
local CheckInterface = {
Hello = Guard.String,
World = Guard.Number,
}
local function Check(UnknownValue: unknown)
assert(type(UnknownValue) == "table")
local Value: any = UnknownValue
return {
Hello = CheckInterface.Hello(Value.Hello),
World = CheckInterface.World(Value.World),
}
end
Check({
Hello = "String",
World = 10,
}) -- Passes and returns {Hello = "String", World = 10}
Check({
Hello = 10,
World = "String",
}) -- Fails and errors
local CheckInterface = {
Hello = Guard.String,
World = Guard.Number,
}
local function Check(UnknownValue: unknown)
assert(type(UnknownValue) == "table")
local Value: any = UnknownValue
return {
Hello = CheckInterface.Hello(Value.Hello),
World = CheckInterface.World(Value.World),
}
end
Check({
Hello = "String",
World = 10,
}) -- Passes and returns {Hello = "String", World = 10}
Check({
Hello = 10,
World = "String",
}) -- Fails and errors
These interface check functions are large and unwieldy, however they are the best option for the moment.
Luau Primitive Types
Guard.Any
A check that passes any value.
local Value = Guard.Any(1) -- Passes and returns 1
local Value = Guard.Any("Hello") -- Passes and returns "Hello"
local Value = Guard.Any({}) -- Passes and returns {}
local Value = Guard.Any(1) -- Passes and returns 1
local Value = Guard.Any("Hello") -- Passes and returns "Hello"
local Value = Guard.Any({}) -- Passes and returns {}
Guard.Boolean
A check that passes boolean values.
local Value = Guard.Boolean(true) -- Passes and returns true
local Value = Guard.Boolean(false) -- Passes and returns false
local Value = Guard.Boolean(1) -- Fails and errors
local Value = Guard.Boolean("Hello") -- Fails and errors
local Value = Guard.Boolean({}) -- Fails and errors
local Value = Guard.Boolean(true) -- Passes and returns true
local Value = Guard.Boolean(false) -- Passes and returns false
local Value = Guard.Boolean(1) -- Fails and errors
local Value = Guard.Boolean("Hello") -- Fails and errors
local Value = Guard.Boolean({}) -- Fails and errors
Guard.Thread
A check that passes thread values.
local Value = Guard.Thread(coroutine.create(function() end)) -- Passes and returns the thread
local Value = Guard.Thread(coroutine.running()) -- Passes and returns the thread
local Value = Guard.Thread(task.spawn(function() end)) -- Passes and returns the thread
local Value = Guard.Thread(1) -- Fails and errors
local Value = Guard.Thread("Hello") -- Fails and errors
local Value = Guard.Thread({}) -- Fails and errors
local Value = Guard.Thread(coroutine.create(function() end)) -- Passes and returns the thread
local Value = Guard.Thread(coroutine.running()) -- Passes and returns the thread
local Value = Guard.Thread(task.spawn(function() end)) -- Passes and returns the thread
local Value = Guard.Thread(1) -- Fails and errors
local Value = Guard.Thread("Hello") -- Fails and errors
local Value = Guard.Thread({}) -- Fails and errors
Guard.Nil
A check that passes nil values.
local Value = Guard.Nil(nil) -- Passes and returns nil
local Value = Guard.Nil(1) -- Fails and errors
local Value = Guard.Nil("Hello") -- Fails and errors
local Value = Guard.Nil({}) -- Fails and errors
local Value = Guard.Nil(nil) -- Passes and returns nil
local Value = Guard.Nil(1) -- Fails and errors
local Value = Guard.Nil("Hello") -- Fails and errors
local Value = Guard.Nil({}) -- Fails and errors
Guard.Number
A check that passes number values.
local Value = Guard.Number(1) -- Passes and returns 1
local Value = Guard.Number(1.5) -- Passes and returns 1.5
local Value = Guard.Number("Hello") -- Fails and errors
local Value = Guard.Number({}) -- Fails and errors
local Value = Guard.Number(1) -- Passes and returns 1
local Value = Guard.Number(1.5) -- Passes and returns 1.5
local Value = Guard.Number("Hello") -- Fails and errors
local Value = Guard.Number({}) -- Fails and errors
Guard.String
A check that passes string values.
local Value = Guard.String("Hello") -- Passes and returns "Hello"
local Value = Guard.String(1) -- Fails and errors
local Value = Guard.String({}) -- Fails and errors
local Value = Guard.String("Hello") -- Passes and returns "Hello"
local Value = Guard.String(1) -- Fails and errors
local Value = Guard.String({}) -- Fails and errors
Combination Types
Guard.Or
Returns a check that passes values that pass at least one of the two given checks.
local NumberOrStringCheck = Guard.Or(Guard.Number, Guard.String)
local Value = NumberOrStringCheck(1) -- Passes and returns 1
local Value = NumberOrStringCheck("Hello") -- Passes and returns "Hello"
local Value = NumberOrStringCheck({}) -- Fails and errors
local NumberOrStringCheck = Guard.Or(Guard.Number, Guard.String)
local Value = NumberOrStringCheck(1) -- Passes and returns 1
local Value = NumberOrStringCheck("Hello") -- Passes and returns "Hello"
local Value = NumberOrStringCheck({}) -- Fails and errors
You can only pass two checks to Or
, if you want to pass more than two checks then you can chain Or
calls:
local NumberOrStringOrBooleanCheck = Guard.Or(
Guard.Number,
Guard.Or(Guard.String, Guard.Boolean)
)
local Value = NumberOrStringOrBooleanCheck(1) -- Passes and returns 1
local Value = NumberOrStringOrBooleanCheck("Hello") -- Passes and returns "Hello"
local Value = NumberOrStringOrBooleanCheck(true) -- Passes and returns true
local Value = NumberOrStringOrBooleanCheck({}) -- Fails and errors
local NumberOrStringOrBooleanCheck = Guard.Or(
Guard.Number,
Guard.Or(Guard.String, Guard.Boolean)
)
local Value = NumberOrStringOrBooleanCheck(1) -- Passes and returns 1
local Value = NumberOrStringOrBooleanCheck("Hello") -- Passes and returns "Hello"
local Value = NumberOrStringOrBooleanCheck(true) -- Passes and returns true
local Value = NumberOrStringOrBooleanCheck({}) -- Fails and errors
Guard.And
Returns a check that passes values that pass both of the two given checks.
-- You can create and use custom check functions!
local NumberAndStringCheck = Guard.And(Guard.Number, function(Value: number)
assert(Value > 0)
return true
end)
local Value = NumberAndStringCheck(1) -- Passes and returns 1
local Value = NumberAndStringCheck(2) -- Passes and returns 2
local Value = NumberAndStringCheck(-1) -- Fails and errors
local Value = NumberAndStringCheck("Hello") -- Fails and errors
-- You can create and use custom check functions!
local NumberAndStringCheck = Guard.And(Guard.Number, function(Value: number)
assert(Value > 0)
return true
end)
local Value = NumberAndStringCheck(1) -- Passes and returns 1
local Value = NumberAndStringCheck(2) -- Passes and returns 2
local Value = NumberAndStringCheck(-1) -- Fails and errors
local Value = NumberAndStringCheck("Hello") -- Fails and errors
Guard.Optional
Returns a check that passes values of the given check or nil.
local OptionalNumberCheck = Guard.Optional(Guard.Number)
local Value = OptionalNumberCheck(1) -- Passes and returns 1
local Value = OptionalNumberCheck(nil) -- Passes and returns nil
local Value = OptionalNumberCheck("Hello") -- Fails and errors
local Value = OptionalNumberCheck({}) -- Fails and errors
local OptionalNumberCheck = Guard.Optional(Guard.Number)
local Value = OptionalNumberCheck(1) -- Passes and returns 1
local Value = OptionalNumberCheck(nil) -- Passes and returns nil
local Value = OptionalNumberCheck("Hello") -- Fails and errors
local Value = OptionalNumberCheck({}) -- Fails and errors
Guard.Literal
Returns a check that passes values that are equal to the given literal.
local LiteralHelloCheck = Guard.Literal("Hello")
local Value = LiteralHelloCheck("Hello") -- Passes and returns "Hello"
local Value = LiteralHelloCheck("World") -- Fails and errors
local Value = LiteralHelloCheck(1) -- Fails and errors
local Value = LiteralHelloCheck({}) -- Fails and errors
local LiteralHelloCheck = Guard.Literal("Hello")
local Value = LiteralHelloCheck("Hello") -- Passes and returns "Hello"
local Value = LiteralHelloCheck("World") -- Fails and errors
local Value = LiteralHelloCheck(1) -- Fails and errors
local Value = LiteralHelloCheck({}) -- Fails and errors
Complex Types
Guard.Map
Returns a check that checks every key and value in a table.
local StringNumberMapCheck = Guard.Map(Guard.String, Guard.Number)
local Value = StringNumberMapCheck({Hello = 1, World = 2}) -- Passes and returns {Hello = 1, World = 2}
local Value = StringNumberMapCheck({}) -- Passes and returns {}
local Value = StringNumberMapCheck({Hello = 1, World = "2"}) -- Fails and errors
local Value = StringNumberMapCheck({Hello = 1, World = 2, 3}) -- Fails and errors
local Value = StringNumberMapCheck("Hello World") -- Fails and errors
local StringNumberMapCheck = Guard.Map(Guard.String, Guard.Number)
local Value = StringNumberMapCheck({Hello = 1, World = 2}) -- Passes and returns {Hello = 1, World = 2}
local Value = StringNumberMapCheck({}) -- Passes and returns {}
local Value = StringNumberMapCheck({Hello = 1, World = "2"}) -- Fails and errors
local Value = StringNumberMapCheck({Hello = 1, World = 2, 3}) -- Fails and errors
local Value = StringNumberMapCheck("Hello World") -- Fails and errors
Guard.Set
Returns a check that validates every value is true and every key passes the given check.
local StringSetCheck = Guard.Set(Guard.String)
local Value = StringSetCheck({Hello = true, World = true}) -- Passes and returns {Hello = true, World = true}
local Value = StringSetCheck({}) -- Passes and returns {}
local Value = StringSetCheck({Hello = true, World = 2}) -- Fails and errors
local Value = StringSetCheck({Hello = true, World = true, 3}) -- Fails and errors
local Value = StringSetCheck("Hello World") -- Fails and errors
local StringSetCheck = Guard.Set(Guard.String)
local Value = StringSetCheck({Hello = true, World = true}) -- Passes and returns {Hello = true, World = true}
local Value = StringSetCheck({}) -- Passes and returns {}
local Value = StringSetCheck({Hello = true, World = 2}) -- Fails and errors
local Value = StringSetCheck({Hello = true, World = true, 3}) -- Fails and errors
local Value = StringSetCheck("Hello World") -- Fails and errors
Guard.List
Returns a check that validates every value passes the given check.
local NumberListCheck = Guard.List(Guard.Number)
local Value = NumberListCheck({1, 2, 3}) -- Passes and returns {1, 2, 3}
local Value = NumberListCheck({}) -- Passes and returns {}
local Value = NumberListCheck({1, 2, "3"}) -- Fails and errors
local Value = NumberListCheck("Hello World") -- Fails and errors
local NumberListCheck = Guard.List(Guard.Number)
local Value = NumberListCheck({1, 2, 3}) -- Passes and returns {1, 2, 3}
local Value = NumberListCheck({}) -- Passes and returns {}
local Value = NumberListCheck({1, 2, "3"}) -- Fails and errors
local Value = NumberListCheck("Hello World") -- Fails and errors
Number Types
Guard.Integer
A check that passes integer values.
local Value = Guard.Integer(1) -- Passes and returns 1
local Value = Guard.Integer(2) -- Passes and returns 2
local Value = Guard.Integer(1.5) -- Fails and errors
local Value = Guard.Integer("Hello") -- Fails and errors
local Value = Guard.Integer({}) -- Fails and errors
local Value = Guard.Integer(1) -- Passes and returns 1
local Value = Guard.Integer(2) -- Passes and returns 2
local Value = Guard.Integer(1.5) -- Fails and errors
local Value = Guard.Integer("Hello") -- Fails and errors
local Value = Guard.Integer({}) -- Fails and errors
Guard.NumberMin
Returns a check that passes number values greater than or equal to the given minimum.
local NumberMinCheck = Guard.NumberMin(5)
local Value = NumberMinCheck(6) -- Passes and returns 1
local Value = NumberMinCheck(7) -- Passes and returns 2
local Value = NumberMinCheck(5) -- Fails and errors
local Value = NumberMinCheck(4) -- Fails and errors
local Value = NumberMinCheck("Hello") -- Fails and errors
local Value = NumberMinCheck({}) -- Fails and errors
local NumberMinCheck = Guard.NumberMin(5)
local Value = NumberMinCheck(6) -- Passes and returns 1
local Value = NumberMinCheck(7) -- Passes and returns 2
local Value = NumberMinCheck(5) -- Fails and errors
local Value = NumberMinCheck(4) -- Fails and errors
local Value = NumberMinCheck("Hello") -- Fails and errors
local Value = NumberMinCheck({}) -- Fails and errors
Guard.NumberMax
Returns a check that passes number values less than or equal to the given maximum.
local NumberMaxCheck = Guard.NumberMax(5)
local Value = NumberMaxCheck(4) -- Passes and returns 1
local Value = NumberMaxCheck(3) -- Passes and returns 2
local Value = NumberMaxCheck(5) -- Fails and errors
local Value = NumberMaxCheck(6) -- Fails and errors
local Value = NumberMaxCheck("Hello") -- Fails and errors
local Value = NumberMaxCheck({}) -- Fails and errors
local NumberMaxCheck = Guard.NumberMax(5)
local Value = NumberMaxCheck(4) -- Passes and returns 1
local Value = NumberMaxCheck(3) -- Passes and returns 2
local Value = NumberMaxCheck(5) -- Fails and errors
local Value = NumberMaxCheck(6) -- Fails and errors
local Value = NumberMaxCheck("Hello") -- Fails and errors
local Value = NumberMaxCheck({}) -- Fails and errors
Guard.NumberMinMax
Returns a check that passes number values between the given minimum and maximum.
local NumberMinMaxCheck = Guard.NumberMinMax(5, 10)
local Value = NumberMinMaxCheck(6) -- Passes and returns 1
local Value = NumberMinMaxCheck(7) -- Passes and returns 2
local Value = NumberMinMaxCheck(5) -- Fails and errors
local Value = NumberMinMaxCheck(4) -- Fails and errors
local Value = NumberMinMaxCheck(10) -- Fails and errors
local Value = NumberMinMaxCheck(11) -- Fails and errors
local Value = NumberMinMaxCheck("Hello") -- Fails and errors
local Value = NumberMinMaxCheck({}) -- Fails and errors
local NumberMinMaxCheck = Guard.NumberMinMax(5, 10)
local Value = NumberMinMaxCheck(6) -- Passes and returns 1
local Value = NumberMinMaxCheck(7) -- Passes and returns 2
local Value = NumberMinMaxCheck(5) -- Fails and errors
local Value = NumberMinMaxCheck(4) -- Fails and errors
local Value = NumberMinMaxCheck(10) -- Fails and errors
local Value = NumberMinMaxCheck(11) -- Fails and errors
local Value = NumberMinMaxCheck("Hello") -- Fails and errors
local Value = NumberMinMaxCheck({}) -- Fails and errors
Roblox Types
Guard only has built-in support for a select number of commonly used Roblox types. If you need to check a type that is not supported, you can create your own check function that does just that:
local function BrickColorCheck(Value: unknown)
assert(typeof(Value) == "BrickColor")
return Value
end
local function BrickColorCheck(Value: unknown)
assert(typeof(Value) == "BrickColor")
return Value
end
Guard.CFrame
A check that passes CFrame values.
local Value = Guard.CFrame(CFrame.new()) -- Passes and returns the CFrame
local Value = Guard.CFrame(1) -- Fails and errors
local Value = Guard.CFrame("Hello") -- Fails and errors
local Value = Guard.CFrame({}) -- Fails and errors
local Value = Guard.CFrame(CFrame.new()) -- Passes and returns the CFrame
local Value = Guard.CFrame(1) -- Fails and errors
local Value = Guard.CFrame("Hello") -- Fails and errors
local Value = Guard.CFrame({}) -- Fails and errors
Guard.Color3
A check that passes Color3 values.
local Value = Guard.Color3(Color3.new()) -- Passes and returns the Color3
local Value = Guard.Color3(1) -- Fails and errors
local Value = Guard.Color3("Hello") -- Fails and errors
local Value = Guard.Color3({}) -- Fails and errors
local Value = Guard.Color3(Color3.new()) -- Passes and returns the Color3
local Value = Guard.Color3(1) -- Fails and errors
local Value = Guard.Color3("Hello") -- Fails and errors
local Value = Guard.Color3({}) -- Fails and errors
Guard.DateTime
A check that passes DateTime values.
local Value = Guard.DateTime(DateTime.now()) -- Passes and returns the DateTime
local Value = Guard.DateTime(1) -- Fails and errors
local Value = Guard.DateTime("Hello") -- Fails and errors
local Value = Guard.DateTime({}) -- Fails and errors
local Value = Guard.DateTime(DateTime.now()) -- Passes and returns the DateTime
local Value = Guard.DateTime(1) -- Fails and errors
local Value = Guard.DateTime("Hello") -- Fails and errors
local Value = Guard.DateTime({}) -- Fails and errors
Guard.Instance
A check that passes Instance values.
local Value = Guard.Instance(Instance.new("Part")) -- Passes and returns the Instance
local Value = Guard.Instance(1) -- Fails and errors
local Value = Guard.Instance("Hello") -- Fails and errors
local Value = Guard.Instance({}) -- Fails and errors
local Value = Guard.Instance(Instance.new("Part")) -- Passes and returns the Instance
local Value = Guard.Instance(1) -- Fails and errors
local Value = Guard.Instance("Hello") -- Fails and errors
local Value = Guard.Instance({}) -- Fails and errors
Guard.Vector2
A check that passes Vector2 values.
local Value = Guard.Vector2(Vector2.new()) -- Passes and returns the Vector2
local Value = Guard.Vector2(1) -- Fails and errors
local Value = Guard.Vector2("Hello") -- Fails and errors
local Value = Guard.Vector2({}) -- Fails and errors
local Value = Guard.Vector2(Vector2.new()) -- Passes and returns the Vector2
local Value = Guard.Vector2(1) -- Fails and errors
local Value = Guard.Vector2("Hello") -- Fails and errors
local Value = Guard.Vector2({}) -- Fails and errors
Guard.Vector2int16
A check that passes Vector2int16 values.
local Value = Guard.Vector2int16(Vector2int16.new()) -- Passes and returns the Vector2int16
local Value = Guard.Vector2int16(1) -- Fails and errors
local Value = Guard.Vector2int16("Hello") -- Fails and errors
local Value = Guard.Vector2int16({}) -- Fails and errors
local Value = Guard.Vector2int16(Vector2int16.new()) -- Passes and returns the Vector2int16
local Value = Guard.Vector2int16(1) -- Fails and errors
local Value = Guard.Vector2int16("Hello") -- Fails and errors
local Value = Guard.Vector2int16({}) -- Fails and errors
Guard.Vector3
A check that passes Vector3 values.
local Value = Guard.Vector3(Vector3.new()) -- Passes and returns the Vector3
local Value = Guard.Vector3(1) -- Fails and errors
local Value = Guard.Vector3("Hello") -- Fails and errors
local Value = Guard.Vector3({}) -- Fails and errors
local Value = Guard.Vector3(Vector3.new()) -- Passes and returns the Vector3
local Value = Guard.Vector3(1) -- Fails and errors
local Value = Guard.Vector3("Hello") -- Fails and errors
local Value = Guard.Vector3({}) -- Fails and errors
Guard.Vector3int16
A check that passes Vector3int16 values.
local Value = Guard.Vector3int16(Vector3int16.new()) -- Passes and returns the Vector3int16
local Value = Guard.Vector3int16(1) -- Fails and errors
local Value = Guard.Vector3int16("Hello") -- Fails and errors
local Value = Guard.Vector3int16({}) -- Fails and errors
local Value = Guard.Vector3int16(Vector3int16.new()) -- Passes and returns the Vector3int16
local Value = Guard.Vector3int16(1) -- Fails and errors
local Value = Guard.Vector3int16("Hello") -- Fails and errors
local Value = Guard.Vector3int16({}) -- Fails and errors
Guard.Check
Returns a check that returns true if the given check passes, and false if it fails.
local NumberCheck = Guard.Check(Guard.Number)
local Pass, Value = NumberCheck(1) -- Passes and returns true, 1
local Pass, Value = NumberCheck("Hello") -- Fails and returns false, nil
local NumberCheck = Guard.Check(Guard.Number)
local Pass, Value = NumberCheck(1) -- Passes and returns true, 1
local Pass, Value = NumberCheck("Hello") -- Fails and returns false, nil