luau-types
Skill12 starsChanged 8 months agoMITView on GitHub
Use for Luau type-system work focused on strictness modes, annotations, inference-aware API design, generics, refinements, advanced type patterns, and Roblox-aware type usage at the type level.
In this repository8 other files it gives its agents.
- luau-coreSkill
- luau-performanceSkill
- roblox-apiSkill
- roblox-cloudSkill
- roblox-coreSkill
- roblox-dataSkill
- roblox-networkingSkill
- roblox-oauthSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
22 rules. About 0 are common, 13 are distinctive, and 9 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈13
Distinctive · estimate
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 10
Use this skill when the task is primarily about Luau's type system:
- Distinctive: line 20
Do not use this skill when the task is mainly about:
- Distinctive: line 28
Use this skill if the core question is "what should this type be?" or "how should this code type-check over time?"
- Very specific: line 29
Prefer --!strict guidance for new or actively maintained code unless the task explicitly targets transitional or legacy code.
- Distinctive: line 30
Prefer inference-preserving designs over annotation-heavy designs when the inferred shape stays precise and readable.
- Distinctive: line 31
Prefer explicit exported aliases at module boundaries when consumers should share a stable contract.
- Very specific: line 32
Use generics when the relationship between inputs and outputs matters.
- Distinctive: line 33
Use tagged unions plus refinements when a value can be one of several structured cases.
- Very specific: line 34
If the task shifts into pure language syntax, hand off to luau-core.
- Very specific: line 35
If the task shifts into optimization or runtime cost tradeoffs, hand off to luau-performance.
- Very specific: line 36
If the task requires Roblox runtime architecture beyond type names and type refinement, use the appropriate roblox/* skill instead.
- Distinctive: line 37
If unsure, exclude anything that is not directly needed to improve typing correctness, maintainability, or analyzer behavior.
- Distinctive: line 41
Start by identifying the file mode expectation:
- Distinctive: line 46
Prefer concrete aliases for shared shapes:
- Distinctive: line 51
Use optionals, unions, and intersections deliberately:
- Very specific: line 55
Treat casts with :: as a precision tool, not a bypass.
- Very specific: line 59
avoid defaulting to any when a type parameter can express intent.
- Distinctive: line 65
Keep module API surfaces type-safe:
- Distinctive: line 67
keep implementation details internal,
- Very specific: line 69
Use Roblox type knowledge only for annotations and refinements, such as Instance, Part, Enum.Material, datatypes, and IsA-driven narrowing.
- Distinctive: line 81
Do not open other skill references unless the request clearly crosses skill boundaries.
- Very specific: line 94
No general syntax tutorial, performance advice, or networking/data/cloud guidance is included.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
luau-types
When to Use
Use this skill when the task is primarily about Luau's type system:
- Choosing between
--!strict,--!nonstrict, and other file type-checking modes. - Adding or correcting type annotations on variables, functions, tables, and modules.
- Designing APIs that preserve inference instead of collapsing to
any. - Modeling data with generics, unions, intersections, optionals, and tagged unions.
- Typing object-like tables, metatable-backed modules, and exported module surfaces.
- Writing or reviewing type functions and other advanced type-level utilities.
- Using Roblox class, datatype, enum, or
IsAknowledge only to improve static typing.
Do not use this skill when the task is mainly about:
- General Luau syntax, control flow, metatables, or standard-library usage outside typing concerns.
- Runtime performance, profiling, hot-path tuning, or allocation strategy.
- Roblox networking, replication, data storage, cloud APIs, or gameplay architecture.
Decision Rules
- Use this skill if the core question is "what should this type be?" or "how should this code type-check over time?"
- Prefer
--!strictguidance for new or actively maintained code unless the task explicitly targets transitional or legacy code. - Prefer inference-preserving designs over annotation-heavy designs when the inferred shape stays precise and readable.
- Prefer explicit exported aliases at module boundaries when consumers should share a stable contract.
- Use generics when the relationship between inputs and outputs matters; do not replace that relationship with
any. - Use tagged unions plus refinements when a value can be one of several structured cases.
- If the task shifts into pure language syntax, hand off to
luau-core. - If the task shifts into optimization or runtime cost tradeoffs, hand off to
luau-performance. - If the task requires Roblox runtime architecture beyond type names and type refinement, use the appropriate
roblox/*skill instead. - If unsure, exclude anything that is not directly needed to improve typing correctness, maintainability, or analyzer behavior.
Instructions
- Start by identifying the file mode expectation:
--!strictfor strong inference and early error detection.--!nonstrictfor transitional code where unresolved values would otherwise become noisy.--!nocheckonly when the task explicitly requires disabled analysis.
- Preserve useful inference before adding annotations everywhere. Add annotations where they clarify intent, stabilize module contracts, constrain
self, or prevent unwanted widening toany. - Prefer concrete aliases for shared shapes:
- records for structured data,
- indexers for dictionaries,
{T}for arrays,- exported aliases for module-facing contracts.
- Use optionals, unions, and intersections deliberately:
T?forT | nil,- tagged unions for state machines or result-like values,
- intersections to combine compatible table capabilities or function signatures.
- Treat casts with
::as a precision tool, not a bypass. Use them to narrow overly generic inference, not to hide unrelated-type errors. - Design generics around relationships:
- preserve element type through transforms,
- carry key/value relationships through containers,
- avoid defaulting to
anywhen a type parameter can express intent.
- Model tables according to how Luau analyzes them:
- unsealed tables can accumulate fields locally,
- annotated or returned tables become sealed,
- width subtyping applies to sealed records.
- For object-like modules, separate instance data from class behavior, derive the instance type from
setmetatable, and annotateselfexplicitly when methods need the shared class type. - Keep module API surfaces type-safe:
- export named aliases for consumer-facing data,
- keep implementation details internal,
- choose signatures that infer caller types cleanly.
- Use Roblox type knowledge only for annotations and refinements, such as
Instance,Part,Enum.Material, datatypes, andIsA-driven narrowing.
Using References
- Open
references/type-system-overview.mdfor file modes, structural typing, annotations, casts, and module-boundary guidance. - Open
references/basic-types-and-table-typing.mdfor builtin types, special types likeanyandunknown, function signatures, table states, and indexers. - Open
references/generics.mdfor generic aliases, generic functions, defaults on aliases, and inference-preserving container patterns. - Open
references/unions-and-intersections.mdfor result shapes, tagged unions, discriminants, and safe intersection usage. - Open
references/refinements.mdfor truthy checks,type(...)guards, equality narrowing, compound conditions, andassert-based narrowing. - Open
references/object-oriented-typing.mdfor metatable-backed class typing,selfannotations, constructor return types, and exported instance aliases. - Open
references/type-functions.mdfor analysis-time type computation, available libraries, and when advanced type-level transforms are justified. - Open
references/roblox-types-in-luau.mdfor Roblox class, datatype, enum, constructor, service, andIsAtyping behavior. - Do not open other skill references unless the request clearly crosses skill boundaries.
Checklist
- The chosen type-checking mode matches the maintenance goal of the file.
- Public module contracts are explicit where reuse matters.
- Inference is preserved where it remains precise.
anyis avoided unless intentionally opting out.- Tables are typed according to their actual shape and sealing behavior.
- Unions, intersections, and optionals reflect real states instead of vague catch-all types.
- Generic parameters encode input/output relationships that callers rely on.
- Method
selftyping is explicit where Luau cannot safely infer the shared class type. - Roblox types are used only to improve typing, not to drift into unrelated Roblox architecture.
- No general syntax tutorial, performance advice, or networking/data/cloud guidance is included.
Common Mistakes
- Leaving a variable unannotated in
--!nonstrictand unintentionally turning it intoany. - Replacing a useful generic relationship with
anyor an overly broad union. - Sealing a table too early with an annotation, then expecting to add fields later.
- Expecting method definitions with
:to automatically share a preciseselftype across the whole class. - Using
::to force unrelated conversions instead of fixing the underlying type design. - Building unions without a discriminant, then making downstream refinement difficult.
- Using intersections between incompatible primitives such as
string & number. - Mixing runtime Roblox architecture guidance into a type-only task.
Examples
Export a stable module contract
--!strict
export type User = {
id: number,
name: string,
nickname: string?,
}
local M = {}
function M.makeUser(id: number, name: string): User
return {
id = id,
name = name,
nickname = nil,
}
end
return MPreserve relationships with a generic function
--!strict
local function first<T>(items: {T}): T?
return items[1]
end
local a = first({1, 2, 3}) -- number?
local b = first({"x", "y"}) -- string?Refine a tagged union
--!strict
type Loading = { kind: "loading" }
type Ready<T> = { kind: "ready", value: T }
type Failed = { kind: "failed", message: string }
type State<T> = Loading | Ready<T> | Failed
local function readValue(state: State<number>): number?
if state.kind == "ready" then
return state.value
end
return nil
endType an object-like module with explicit self
--!strict
local Counter = {}
Counter.__index = Counter
type CounterData = {
value: number,
}
export type Counter = typeof(setmetatable({} :: CounterData, Counter))
function Counter.new(initialValue: number): Counter
return setmetatable({
value = initialValue,
}, Counter)
end
function Counter.increment(self: Counter, amount: number): number
self.value += amount
return self.value
end
return CounterDoes it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

