{"id":15888208,"url":"https://github.com/corecii/greentea","last_synced_at":"2026-01-12T02:11:10.900Z","repository":{"id":237620649,"uuid":"794880285","full_name":"Corecii/GreenTea","owner":"Corecii","description":"A runtime typechecker with Luau types, pretty errors, and inspection","archived":false,"fork":false,"pushed_at":"2025-01-01T00:17:50.000Z","size":2512,"stargazers_count":23,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-02T16:51:18.520Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Luau","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Corecii.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-05-02T06:27:59.000Z","updated_at":"2025-03-11T20:06:53.000Z","dependencies_parsed_at":"2024-10-27T23:47:04.066Z","dependency_job_id":"e3b1df3d-2f68-4fba-a601-3a620d41d1d7","html_url":"https://github.com/Corecii/GreenTea","commit_stats":null,"previous_names":["corecii/greentea"],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/Corecii/GreenTea","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Corecii%2FGreenTea","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Corecii%2FGreenTea/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Corecii%2FGreenTea/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Corecii%2FGreenTea/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Corecii","download_url":"https://codeload.github.com/Corecii/GreenTea/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Corecii%2FGreenTea/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28331717,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T00:36:25.062Z","status":"online","status_checked_at":"2026-01-12T02:00:08.677Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-06T06:06:40.686Z","updated_at":"2026-01-12T02:11:10.885Z","avatar_url":"https://github.com/Corecii.png","language":"Luau","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🍵 GreenTea\nAn experimental runtime typechecker for Roblox Luau, with matching 'tooling-time' Luau types.\n\n[Docs](https://corecii.github.io/GreenTea/)\n\n## Features\n- Check types at runtime (like [the t package](https://github.com/osyrisrblx/t))\n- Build Luau types and runtime types simultaneously (so you have less duplicate code!)\n- Pretty errors that tell you exactly where you went wrong, even for unions and intersections\n- Inspect types at runtime, so you can procedurally check types in weird scenarios, such as when checking a set of Instance attributes.\n- Infer types from values\n- `t` compatibility (via `GreenTea.t` — all `t` tests pass!)\n\n## Experimental\nWhile this package has had a lot of work put into it, it's largely an experiment. It's a first iteration, so the API can use some improvement — especially the structure of the generated Type objects, which could have a better shape.\n\nPlease leave feedback on the issues page. Thank you!\n\n## Install\n\n### with Wally (for Rojo)\n1. [Install Wally](https://wally.run/install)\n2. Add `GreenTea = \"corecii/greentea@0.4.11\"` to your `wally.toml`\n\n### with pesde (for Rojo or Lune)\n1. [Install pesde](https://docs.pesde.daimond113.com/installation)\n2. Run `pesde add corecii/greentea`\\\n   or add `GreenTea = { name = \"corecii/greentea\", version = \"^0.4.11\" }` to your `pesde.toml`\n\n### Standalone (for non-Rojo)\n- Download from [the Releases page](https://github.com/corecii/greentea/releases)\n\n## How Does It Work?\n\nGreenTea's runtime code looks like a typical runtime typechecker:\nyou call functions to create typecheckers and compose them together.\n\nIt has two tricks:\n1. Its function type definitions _lie_ and say that it's returning _the type that you're checking for_ instead of a GreenTea.Type object.\n  So while you're composing a runtime type, you're _also_ composing a Luau type definition!\n2. The typechecker it produces is actually an _object_, which gives you a runtime-inspectable\n  type definition you can do more advanced stuff with. This also means prettier errors that look a lot like Luau type errors.\n\n## Examples\n\n### Easy Mode\n\n```lua\nlocal gt = require(path.to.GreenTea)\n\nlocal stringType = gt.build(gt.string())\n\n-- equivalent to takesString(value: string)\nlocal function takesString(value: typeof(stringType:type()))\n\t-- will error if value is not a string\n\tstringType:assert(value)\n\n\t-- ...\nend\n```\n\nUsing `gt` is recommended, because `GreenTea` is a lot to type and `gt` is not!\n\n### How it Works\n\n```lua\nlocal stringTypeRaw = gt.string()\n\n-- stringTypeRaw is typed in Luau as `string`\n-- but at runtime, it's really a GreenTea.Type object.\n-- This makes it easy to split it up into a runtime\n-- typechecker and a Luau type:\n\n-- give a name to the type\ntype stringTypeLuau = typeof(stringTypeRaw:type())\n\n-- cast the object to the runtime typechecker type it really is\nlocal stringTypeChecker = gt.typecast(stringTypeRaw)\n\n-- You can think of this like \"tricking\" Luau into\n-- \"giving\" us a `string` type.\n-- This is all `GreenTea.build` does -- it typecasts\n-- the value into a GreenTea.Type object, but includes\n-- the original type os you can use `typeof`.\n\n-- But the magic is this also works for more complex types!\n\nlocal catTypeRaw = gt.table({\n\tage = gt.number(),\n\tmeowSound = gt.string(),\n\tbreed = {\n\t\t[gt.string()] = gt.number(),\n\t},\n})\n\ntype catTypeLuau = typeof(catTypeRaw)\n-- which is the same as...\ntype catTypeSame = {\n\tage: number,\n\tmeowSound: string,\n\tbreed: { [string]: number },\n}\n\n-- and we can get a runtime typechecker...\nlocal catTypeChecker = gt.typecast(catTypeRaw)\n\n-- OR we can make it really easy on ourselves if we just use `build` from the beginning:\n\nlocal catType = gt.build(gt.table{\n\tage = gt.number(),\n\tmeowSound = gt.string(),\n\tbreed = {\n\t\t[gt.indexer(gt.string())] = gt.number(),\n\t},\n}))\n\n-- catType == catTypeChecker\n-- catTypeLuau == typeof(catTypeChecker:type())\n```\n\nUsing `build` is recommended because it makes this mostly type-safe:\n- The returned value is properly typed a GreenTea Type object, so you\n  have typechecked access to GreenTea.Type's properties and methods.\n- TypeObject.type() can still be passed to GreenTea constructors to\n  pass the GreenTea type in.\n- `build` runs `GreenTea.typeof` internally, so you can pass it simple tables\n  and they'll be converted to the proper `GreenTea.table` type.\n\nIn this way, \"built\" types are for direct use, and \"unbuilt\" types are for composition\nwith other GreenTea constructors.\n\n### Taking in GreenTea types\n\nGreenTea is great for libraries that want to do typechecking, like RemoteEvent wrappers, because you can make the API very ergonomic:\n\n```lua\n-- RemoteWrapper.luau\n\nfunction RemoteWrapper.new\u003cT\u003e(greenTeaType: T): RemoteWrapper\u003cT\u003e\n\tlocal self = {\n\t\ttypechecker = GreenTea.build(greenTeaType),\n\t\t...\n\t}\n\n\treturn setmetatable(self, RemoteWrapper)\nend\n\nfunction RemoteWrapper.onServerEvent\u003cT\u003e(self: RemoteWrapper\u003cT\u003e, fn: (player: Player, params: T) -\u003e ())\n\tself.event:OnServerEvent(function(player: Player, paramsMaybe: any?)\n\t\tlocal params = self.typechecker:assert(params)\n\t\tfn(player, params)\n\tend)\nend\n\n```\n```lua\n-- CatSpawner.luau\n\nlocal SpawnCat = RemoteWrapper.new({\n\tcat = {\n\t\tage = gt.number(),\n\t\tmeowSound = gt.string(),\n\t\t...\n\t},\n\tlocation = gt.CFrame(),\n\t...\n})\n\nSpawnVehicle:onServerEvent(function(player, params)\n\t-- params is properly typed as { cat: { age: number, ...}, location: CFrame, ... }\nend)\n```\n\n## Lune Support\n\nGreenTea has not been extensively tested on Lune.\nSome Roblox-specific typecheckers might not work, and there may be other issues.\nPlease report any issues here: https://github.com/corecii/greentea/issues\n\n## `t` Compatibility\n\n`GreenTea.t` includes all of the methods from the `t` package. See [the t package's readme](https://github.com/osyrisrblx/t/blob/master/README.md) for more details.\n\n### As a drop-in replacement\n\nYou can include the `greentea-t-standalone` package as an easy, drop-in replacement for a codebase which already uses `t`. Just add it to your `wally.toml`:\n\n\u003e **with Wally (for Rojo)**\n\u003e 1. [Install Wally](https://wally.run/install)\n\u003e 2. Add `t = \"corecii/greentea-t-standalone@0.4.11\"` to your `wally.toml`\n\n\u003e **with pesde (for Rojo)**\n\u003e 1. [Install pesde](https://docs.pesde.daimond113.com/installation)\n\u003e 2. Add `t = { name = \"corecii/greentea_t_standalone\", version = \"^0.4.11\" }` to your `pesde.toml`\n\nThis package just exports `GreenTea.t` to make drop-in replacement easy.\n\n## Inspiration\n\nThis library was largely inspired by `t`, but also my experience working with t types, working with Luau types, and working with systems that need inspectable type definitions. This is my first attempt at solving all of these problems. I'd really like to see the inversion of this library -- where inspectable runtime type definitions are built from Luau types. But that's more work, so I'll leave it as a TODO!\n\n## Future Plans\n- Split up `GreenTea.luau` into multiple files. It's too long. But I'm tired and want to move on and actually use this library for cool things.\n- Stop lying to the typechecker once it's able to handle all of GreenTea's features.\n- Inverted GreenTea, where runtime typecheckers are built from Luau types.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcorecii%2Fgreentea","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcorecii%2Fgreentea","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcorecii%2Fgreentea/lists"}