[Release] TypeGuard 2.0.0 - Runtime data validation

TypeGuard

Have you ever encountered a situation where Luau types just didn’t cut it?
I have, especially when validating RemoteEvent data that has been sent by a client.
But this could also be useful to make 100% sure that the data you are about to write to your datastore matches a predefined schema.

Download

If you want to try it out for yourself, you can download the module here

Showcase

local tg = require(script.Parent.TypeGuard)

print(tg.PositiveInteger(1234)) -- Expected output: true
print(tg.PositiveInteger(-1234)) -- Expected output: false

local nullableNonEmptyString = tg.Optional(tg.NonEmptyString)

print(nullableNonEmptyString('Hello!')) -- Expected output: true
print(nullableNonEmptyString(nil)) -- Expected output: true
print(nullableNonEmptyString('')) -- Expected output: false

local itemSchema = tg.Dictionary({
    id = tg.NonEmptyString,
    name = tg.NonEmptyString,
    value = tg.Number,
})

local validationSchema = tg.Dictionary({
    level = tg.PositiveInteger,
    cash = tg.Number,
    inventory = tg.Array(itemSchema),
})

print(validationSchema({
    level = 16,
    cash = 12.15,
    inventory = {
        {
            id = 'gold-sword-a65a4fb4c',
            name = 'Gold Sword',
            value = 50.86,
        },
        {
            id = 'iron-sword-b75ce5f3a',
            name = 'Iron Sword',
            value = 5.39,
        },
    },
})) -- Expected output: true

Usage

An example of how to use the module can be found in the Tests script provided in the module.
Feel free to add your own types or suggest them here.

GitHub

If you just wanna take a look at the code, feel free to do so.
You can find the GitHub repository here

3 Likes

I’ve learned the beauty and importance of having both Luau types and runtime type validation – I think they respectively serve different purposes that, when used together, can be very powerful in writing better code. Luau types help you write proper code while runtime type validation is good for use cases like remotes where you want to enforce types on arguments.

This feels like a pretty heavy library though. I’m interested to know what your design decision was for making the validators all classes? For reference, I currently use the t library. All type functions are based in reusable factories and the module is flexible since it returns a boolean and a message if the type doesn’t pass. A lot of the time you might find yourself throwing the returns in an assert but you can otherwise handle non-passing types in any way you’d like.

4 Likes

If luau types didnt cut it, Use roblox-ts. Its very awesome in types. I currently use net and flamework for remotes and the types are amazing. I dont have to do it in runtime, I just set the types and its good to go.

2 Likes

I based my design on an existing library for PHP called Psl. This has both assert and coerce methods for each type. Where coerce attempts to parse some data types for you automatically, like Enums or DateTime values. I thought of adding this functionality later, but I wanted to gather some feedback first.

You might be right that the OOP style I use here might not be ideal. I’ll reconsider it.

1 Like

Would be nice to use, but the game I work on has over 100,000 existing lines of code that contain a lot of garbage.

You are doing something wrong with your code then.

1 Like

Yeah, I know that. Thing is, it isn’t all my code. Multiple developers have worked on the game. Even before I joined the team back in 2017. Tried to revamp it in 2020, but revamping all things at once is just too big of a task. Everyone got demotivated, and now we’re just trying to revamp things one by one.

I have now updated the module using your feedback.