{"id":"raild3x/t","name":"t","scope":"raild3x","platform":"roblox","description":"A runtime typechecker for Luau/Roblox","version":"1.1.0","latest":"1.1.0","versions":["0.1.0","1.0.0","1.1.0"],"license":"MIT","licenseRating":"safe","licenseCaveats":["The package archive does not include its license text; the license is declared in its manifest metadata."],"licenseVerified":false,"dependencies":{},"integrity":"f44bc4bcb0f464f02904842988e6f61b73f63f7216ae81a8ae765cbb19d96807","likes":0,"downloads":0,"install":"forest install raild3x/t","url":"https://forest.dev/p/roblox/raild3x/t","files":"https://api.forest.dev/ai/package/roblox/raild3x/t/files","readme":"<h2 align=\"center\">\n\t<b>T</b><br>A Runtime Type Checker for Luau/Roblox\n</h2>\n\n\n`t` is a library of type validator functions that allow you to easily compose type definitions to check values against.\n\n## Why?\nWhen building large systems, it can often be difficult to find type mismatch bugs.\\\nTypechecking helps you ensure that your functions are recieving the appropriate types for their arguments.\n\nIn Roblox specifically, it is important to type check your Remote objects to ensure that exploiters aren't sending you bad data which can cause your server to error (and potentially crash!).\n\n## Quick Start\n\n```lua\nlocal t = require(path.to.t)\n\nlocal createPlayerArgs = t.tuple(\n\tt.string,\n\tt.numberConstrained(0, 100),\n\tt.optional(t.string)\n)\n\nlocal function createPlayer(name, health, team)\n\tassert(createPlayerArgs(name, health, team))\n\t-- name: string\n\t-- health: number in [0, 100]\n\t-- team: string?\nend\n```\n\n## Basic Validators\n\nPrimitive checks:\n\n- `t.boolean`\n- `t.buffer`\n- `t.thread`\n- `t.callback`\n- `t.none`\n- `t.string`\n- `t.table`\n- `t.userdata`\n- `t.vector`\n- `t.number`\n- `t.nan`\n\nRoblox value types are also exposed directly, for example:\n\n- `t.Instance`\n- `t.CFrame`\n- `t.Color3`\n- `t.Vector3`\n- `t.Enum`\n- `t.EnumItem`\n- ...etc\n\nYou can also build ad hoc checkers with:\n\n- `t.type(typeName)`\n- `t.typeof(typeName)`\n\n```lua\nlocal isVector3 = t.typeof(\"Vector3\")\nprint(isVector3(Vector3.zero)) --> true\n```\n\n## Composition\n\n- `t.any(value)`\n- `t.literal(...)`\n- `t.keyOf(keyTable)`\n- `t.valueOf(valueTable)`\n- `t.optional(check)`\n- `t.where(check, predicate, errorMessage?)`\n- `t.tuple(...)`\n- `t.strictTuple(...)`\n- `t.union(...)` / `t.some(...)`\n- `t.intersection(...)` / `t.every(...)`\n\n```lua\nlocal nonEmptyString = t.where(t.string, function(value)\n\treturn #value > 0, \"string must not be empty\"\nend)\n\nprint(nonEmptyString(\"hello\")) --> true\nprint(nonEmptyString(\"\")) --> false, \"string must not be empty\"\n```\n\n## Tables and Arrays\n\n- `t.keys(check)`\n- `t.values(check)`\n- `t.map(keyCheck, valueCheck)`\n- `t.set(valueCheck)`\n- `t.array(check)`\n- `t.strictArray(...)`\n\n```lua\nlocal tagsCheck = t.set(t.string)\nprint(tagsCheck({ Fast = true, Active = true })) --> true\n```\n\n## Interfaces\n\n- `t.interface(definition)`\n- `t.partialInterface(definition)`\n- `t.strictInterface(definition)`\n\n`t.interface` requires each declared field and allows extra fields.\n\n`t.partialInterface` validates declared fields only when they are present, which is useful for patch payloads and optional update objects.\n\n`t.strictInterface` requires each declared field and rejects extra fields.\n\n```lua\nlocal playerPatch = t.partialInterface({\n\tName = t.string,\n\tHealth = t.numberConstrained(0, 100),\n})\n\nprint(playerPatch({ Name = \"Builderman\" })) --> true\nprint(playerPatch({ Health = 150 })) --> false, \"[partialInterface] bad value for Health: ...\"\n```\n\n## Numbers and Strings\n\nNumeric helpers:\n\n- `t.integer`\n- `t.integerMin(min)`\n- `t.integerMax(max)`\n- `t.integerMinExclusive(min)`\n- `t.integerMaxExclusive(max)`\n- `t.integerConstrained(min, max)`\n- `t.integerConstrainedExclusive(min, max)`\n- `t.integerPositive`\n- `t.integerNegative`\n- `t.numberMin(min)`\n- `t.numberMax(max)`\n- `t.numberMinExclusive(min)`\n- `t.numberMaxExclusive(max)`\n- `t.numberConstrained(min, max)`\n- `t.numberConstrainedExclusive(min, max)`\n- `t.numberPositive`\n- `t.numberNegative`\n\nString helpers:\n\n- `t.match(pattern)`\n\n## Roblox-Specific Validators\n\n- `t.instanceOf(className, childTable?)`\n- `t.instanceIsA(className, childTable?)`\n- `t.children(checkTable)`\n- `t.enum(enum)`\n\n```lua\nlocal buttonCheck = t.instanceIsA(\"GuiButton\")\nlocal materialCheck = t.enum(Enum.Material)\n```\n\n`t.children` fails if more than one relevant child has the same name.\n\n## Function Helpers\n\n- `t.wrap(callback, argCheck)`\n- `t.strict(check)`\n\n```lua\nlocal add = t.wrap(function(a, b)\n\treturn a + b\nend, t.tuple(t.number, t.number))\n\nprint(add(2, 3)) --> 5\n```\n\n## Custom Validators\n\nYou can always compose your own validator directly:\n\n```lua\nlocal t = require(path.to.t)\n\nlocal function isTaggedObject(value)\n\tlocal ok, err = t.table(value)\n\tif not ok then\n\t\treturn false, err\n\tend\n\n\tif value.Tag ~= \"Enemy\" then\n\t\treturn false, \"Enemy-tagged table expected\"\n\tend\n\n\treturn true\nend\n```\n\n## Return Contract\n\nOn failure you get `false` and an error string. On success you get `true` and the second result will be <i>void</i>, <b>NOT nil</b>. \nDo not rely on the exact number of returned values. This is done to keep compatibility with\nthe original T library by [osyrisrblx](https://github.com/osyrisrblx/t)\n\n## Examples\n\nSee the contained spec file for a concrete set of examples covering primitives, composition, interfaces, Roblox-specific checks, and wrapper helpers.\n","readmeTruncated":false}