luau-types
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chineseluau-types
luau-types
When to Use
适用场景
Use this skill when the task is primarily about Luau's type system:
- Choosing between ,
--!strict, and other file type-checking modes.--!nonstrict - 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 knowledge only to improve static typing.
IsA
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.
当任务主要涉及Luau类型系统时使用本指南:
- 在、
--!strict和其他文件类型检查模式之间做选择--!nonstrict - 为变量、函数、表和模块添加或修正类型注解
- 设计能够保留类型推导能力、不会退化为类型的API
any - 使用泛型、联合类型、交叉类型、可选类型、标签联合类型建模数据
- 为类对象表、基于元表的模块、导出的模块对外接口添加类型定义
- 编写或评审类型函数及其他高级类型层面的工具方法
- 仅在优化静态类型时使用Roblox类、数据类型、枚举或相关知识
IsA
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 guidance for new or actively maintained code unless the task explicitly targets transitional or legacy code.
--!strict - 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 skill instead.
roblox/* - If unsure, exclude anything that is not directly needed to improve typing correctness, maintainability, or analyzer behavior.
当任务主要涉及以下内容时不要使用本指南:
- 通用Luau语法、控制流、元表,或和类型无关的标准库使用
- 运行时性能、 profiling、热路径优化或内存分配策略
- Roblox网络、数据同步、存储、云API或游戏玩法架构
Instructions
决策规则
- Start by identifying the file mode expectation:
- for strong inference and early error detection.
--!strict - for transitional code where unresolved values would otherwise become noisy.
--!nonstrict - only when the task explicitly requires disabled analysis.
--!nocheck
- Preserve useful inference before adding annotations everywhere. Add annotations where they clarify intent, stabilize module contracts, constrain , or prevent unwanted widening to
self.any - Prefer concrete aliases for shared shapes:
- records for structured data,
- indexers for dictionaries,
- for arrays,
{T} - exported aliases for module-facing contracts.
- Use optionals, unions, and intersections deliberately:
- for
T?,T | 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 when a type parameter can express intent.
any
- 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 , and annotate
setmetatableexplicitly when methods need the shared class type.self - 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, datatypes, andEnum.Material-driven narrowing.IsA
- 如果核心问题是「这个类型应该是什么?」或「这段代码长期的类型检查应该如何运作?」,则使用本指南
- 对于新代码或正在维护的代码,优先推荐模式,除非任务明确针对过渡阶段或遗留代码
--!strict - 当推导出来的类型足够精确且易读时,优先选择保留类型推导的设计,而非大量使用注解的设计
- 当模块消费者需要稳定的类型契约时,优先在模块边界处使用显式的导出别名
- 当输入和输出之间的类型关联很重要时使用泛型,不要用替代这种关联关系
any - 当一个值可能属于多种结构化类型时,使用标签联合类型加类型细化的方案
- 如果任务转向纯语言语法相关问题,转交给指南处理
luau-core - 如果任务转向优化或运行时成本权衡相关问题,转交给指南处理
luau-performance - 如果任务需要用到除了类型名称和类型细化之外的Roblox运行时架构知识,使用对应的指南
roblox/* - 如果不确定如何处理,排除所有和提升类型正确性、可维护性、分析器行为没有直接关系的内容
Using References
使用指引
- Open for file modes, structural typing, annotations, casts, and module-boundary guidance.
references/type-system-overview.md - Open for builtin types, special types like
references/basic-types-and-table-typing.mdandany, function signatures, table states, and indexers.unknown - Open for generic aliases, generic functions, defaults on aliases, and inference-preserving container patterns.
references/generics.md - Open for result shapes, tagged unions, discriminants, and safe intersection usage.
references/unions-and-intersections.md - Open for truthy checks,
references/refinements.mdguards, equality narrowing, compound conditions, andtype(...)-based narrowing.assert - Open for metatable-backed class typing,
references/object-oriented-typing.mdannotations, constructor return types, and exported instance aliases.self - Open for analysis-time type computation, available libraries, and when advanced type-level transforms are justified.
references/type-functions.md - Open for Roblox class, datatype, enum, constructor, service, and
references/roblox-types-in-luau.mdtyping behavior.IsA - Do not open other skill references unless the request clearly crosses skill boundaries.
- 首先明确文件的类型检查模式预期:
- 用于需要强类型推导和早期错误检测的场景
--!strict - 用于过渡阶段的代码,避免未解析的值产生过多噪音
--!nonstrict - 仅当任务明确要求关闭类型分析时才使用
--!nocheck
- 在大面积添加注解之前优先保留有用的类型推导。仅在需要明确意图、稳定模块契约、约束类型、防止类型意外拓宽为
self时添加注解any - 对于复用的类型结构优先使用具体别名:
- 结构化数据使用记录类型
- 字典使用索引类型
- 数组使用格式
{T} - 模块对外契约使用导出别名
- 有意识地使用可选类型、联合类型和交叉类型:
- 等价于
T?T | nil - 状态机或类结果类型使用标签联合类型
- 合并兼容的表能力或函数签名使用交叉类型
- 把类型转换当作精度调整工具,而不是类型检查绕过手段。仅用它来收窄过于宽泛的推导类型,不要用它来掩盖不相关的类型错误
:: - 围绕类型关联设计泛型:
- 在转换过程中保留元素类型
- 在容器中保留键值类型关联
- 当类型参数可以表达意图时,不要默认使用
any
- 按照Luau的分析规则为表添加类型:
- 未密封的表可以在本地添加字段
- 加了注解或被返回的表会被密封
- 宽度子类型化适用于密封的记录类型
- 对于类对象模块,将实例数据和类行为分离,从推导实例类型,当方法需要共享类类型时显式注解
setmetatableself - 保持模块API接口的类型安全:
- 为面向消费者的数据导出命名别名
- 实现细节保持私有
- 选择能够清晰推导调用方类型的函数签名
- 仅在注解和类型细化时使用Roblox类型知识,例如、
Instance、Part、数据类型和基于Enum.Material的类型收窄IsA
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.
- is avoided unless intentionally opting out.
any - 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 typing is explicit where Luau cannot safely infer the shared class type.
self - 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.
- 打开查看文件模式、结构化类型、注解、类型转换、模块边界相关指引
references/type-system-overview.md - 打开查看内置类型、
references/basic-types-and-table-typing.md和any等特殊类型、函数签名、表状态、索引类型相关内容unknown - 打开查看泛型别名、泛型函数、别名默认值、保留类型推导的容器模式相关内容
references/generics.md - 打开查看结果类型结构、标签联合类型、判别符、安全使用交叉类型相关内容
references/unions-and-intersections.md - 打开查看真值检查、
references/refinements.md守卫、等值收窄、复合条件、基于type(...)的收窄相关内容assert - 打开查看基于元表的类类型定义、
references/object-oriented-typing.md注解、构造函数返回类型、导出实例别名相关内容self - 打开查看分析阶段类型计算、可用库、适用高级类型转换的场景相关内容
references/type-functions.md - 打开查看Roblox类、数据类型、枚举、构造函数、服务、
references/roblox-types-in-luau.md类型行为相关内容IsA - 除非请求明确跨技能边界,否则不要打开其他技能的参考文档
Common Mistakes
检查清单
- Leaving a variable unannotated in and unintentionally turning it into
--!nonstrict.any - Replacing a useful generic relationship with or an overly broad union.
any - Sealing a table too early with an annotation, then expecting to add fields later.
- Expecting method definitions with to automatically share a precise
:type across the whole class.self - 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.
- 选择的类型检查模式符合文件的维护目标
- 公共模块契约在需要复用的地方是显式定义的
- 类型推导在保持精确的场景下被保留
- 除非主动选择退出类型检查,否则避免使用
any - 表的类型符合其实际结构和密封行为
- 联合类型、交叉类型、可选类型反映真实的状态,而非模糊的通用类型
- 泛型参数编码了调用方依赖的输入输出类型关联
- 在Luau无法安全推导共享类类型的地方,方法的类型是显式注解的
self - Roblox类型仅用于优化类型定义,没有偏离到不相关的Roblox架构内容
- 没有包含通用语法教程、性能建议、网络/数据/云服务相关指引
Examples
常见错误
Export a stable module contract
—
luau
--!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 M- 在模式下不给变量加注解,意外让它变成
--!nonstrict类型any - 用或过于宽泛的联合类型替代有用的泛型关联
any - 过早用注解密封一个表,之后又想要添加新字段
- 期望用定义的方法会自动在整个类中共享精确的
:类型self - 使用强制不相关的类型转换,而不修复底层的类型设计
:: - 构建不带判别符的联合类型,导致后续的类型细化变得困难
- 在不兼容的基础类型之间使用交叉类型,例如
string & number - 在仅涉及类型的任务中混入运行时Roblox架构指引
Preserve relationships with a generic function
示例
—
导出稳定的模块契约
luau
--!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?luau
--!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 MRefine a tagged union
使用泛型函数保留类型关联
luau
--!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
endluau
--!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?Type an object-like module with explicit self
self细化标签联合类型
luau
--!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 Counterluau
--!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
end—
为带显式self
的类对象模块添加类型
self—
luau
--!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 Counter