mcpField
L
luau-types

luau-types

github.com/luumenlabs开发13173 次安装22 周前更新
代码仓库

关于 luau-types

luau-types 是面向 Luau 类型系统任务的 Skill,供编写或审查 Luau 代码的开发者使用。它聚焦类型推断、泛型、联合类型、表与模块 API,并避免偏离到运行时优化或 Roblox 架构。

主要功能

  1. 01选择文件类型检查模式
  2. 02为变量、函数和表添加类型
  3. 03设计保留推断的 API
  4. 04建模泛型与联合类型
  5. 05处理模块与元表类型

适用场景

  1. 01为 Luau 文件选择 strict 模式
  2. 02为模块定义稳定的导出类型
  3. 03用泛型保留输入输出关系
  4. 04为状态模型设计带标签联合类型

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/luumenlabs/luau-skills --skill luau-types

安装后在 Claude Code 中输入/luau-types确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
basic-types-and-table-typing.md
generics.md
object-oriented-typing.md
refinements.md
roblox-types-in-luau.md
type-functions.md
type-system-overview.md
unions-and-intersections.md

详细介绍

luau-types

适用场景

当任务主要涉及 Luau 的类型系统时,请使用此技能:

  • 在 --!strict、--!nonstrict 和其他文件类型检查模式之间进行选择。
  • 为变量、函数、表和模块添加或修正类型注解。
  • 设计能够保留类型推断,而不会退化为 any 的 API。
  • 使用泛型、联合类型、交集类型、可选类型和带标签的联合类型来建模数据。
  • 为类对象表、由元表支持的模块以及导出的模块接口添加类型。
  • 编写或审查类型函数和其他高级类型级实用工具。
  • 仅使用 Roblox 类、数据类型、枚举或 IsA 知识来改进静态类型。

当任务主要涉及以下内容时,请勿使用此技能:

  • 与类型无关的一般 Luau 语法、控制流、元表或标准库用法。
  • 运行时性能、性能分析、热点调优或分配策略。
  • Roblox 网络、复制、数据存储、云 API 或游戏架构。

决策规则

  • 如果核心问题是“这个类型应该是什么?”或“这段代码应如何随着时间推移通过类型检查?”,请使用此技能。
  • 对于新代码或积极维护的代码,优先采用 --!strict 指南,除非任务明确针对过渡期或旧版代码。
  • 如果推断出的结构仍然精确且易读,优先采用保留类型推断的设计,而不是大量添加类型注解。
  • 如果模块的使用者需要共享稳定的契约,优先在模块边界显式导出类型别名。
  • 当输入与输出之间的关系很重要时,请使用泛型;不要用 any 取代这种关系。
  • 当一个值可能属于多个结构化情形之一时,请使用带标签的联合类型和类型细化。
  • 如果任务转向纯语言语法,请转交给 luau-core。
  • 如果任务转向优化或运行时成本权衡,请转交给 luau-performance。
  • 如果任务需要的 Roblox 运行时架构超出类型名称和类型细化的范围,请改用适当的 roblox/* 技能。
  • 如有疑问,请排除所有非直接用于提升类型正确性、可维护性或分析器行为的内容。

Instructions

  1. 首先确定文件模式要求:
    • --!strict 用于强化类型推断并及早发现错误。
    • --!nonstrict 用于过渡性代码,避免未解析的值造成过多干扰。
    • 仅在任务明确要求禁用分析时使用 --!nocheck。
  2. 在到处添加注解之前,先保留有用的类型推断。在注解能明确意图、稳定模块契约、约束 self 或避免不必要地扩大为 any 时,再添加注解。
  3. 对共享的数据形状,优先使用具体别名:
    • 结构化数据使用记录。
    • 字典使用索引器。
    • 数组使用 {T}。
    • 面向模块的契约使用导出的别名。
  4. 有意识地使用可选类型、联合类型和交集类型:
    • 用 T? 表示 T | nil。
    • 对状态机或类似结果的值使用带标签的联合类型。
    • 使用交集类型组合兼容的表能力或函数签名。
  5. 将 :: 强制转换视为精确调整类型的工具,而非绕过检查的手段。用它收窄过于宽泛的推断,不要用它掩盖无关类型错误。
  6. 围绕类型之间的关系设计泛型:
    • 在转换过程中保留元素类型。
    • 在容器中保留键和值之间的关系。
    • 当类型参数能够表达意图时,避免默认使用 any。
  7. 根据 Luau 的分析方式对表建模:
    • 未封闭的表可以在本地累积字段。
    • 带注解或作为返回值的表会被封闭。
    • 封闭记录支持宽度子类型。
  8. 对象式模块应将实例数据与类行为分开,从 setmetatable 推导实例类型,并在方法需要共享类类型时显式注解 self。
  9. 确保模块 API 表面具备类型安全性:
    • 为面向使用者的数据导出具名别名。
    • 将实现细节保留在模块内部。
    • 选择能清晰推断调用者类型的签名。
  10. 仅将 Roblox 类型知识用于注解和类型细化,例如 Instance、Part、Enum.Material、数据类型以及由 IsA 驱动的收窄。

使用参考资料

  • 打开 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,了解分析时的类型计算、可用库,以及何时有必要进行高级类型级转换。
  • 打开 references/roblox-types-in-luau.md,了解 Roblox 类、数据类型、枚举、构造函数、服务和 IsA 的类型行为。
  • 除非请求明确涉及其他技能领域,否则不要打开其他技能参考资料。

检查清单

  • 所选的类型检查模式与文件的维护目标相符。
  • 在需要复用的地方明确声明公共模块契约。
  • 在类型推断依然精确时保留推断。
  • 避免使用 any,除非是有意选择不进行类型检查。
  • 根据表的实际形状和封闭行为为其标注类型。
  • 联合类型、交叉类型和可选类型应反映真实状态,而不是含糊的兜底类型。
  • 泛型参数应编码调用方依赖的输入/输出关系。
  • 当 Luau 无法安全推断共享类类型时,应明确标注方法的 self 类型。
  • 仅在有助于改进类型标注时使用 Roblox 类型,避免偏离主题而涉及无关的 Roblox 架构。
  • 不包含通用语法教程、性能建议或网络/数据/云相关指导。

常见错误

  • 在 --!nonstrict 中不为变量添加类型标注,导致其意外变成 any。
  • 用 any 或过于宽泛的联合类型取代有用的泛型关系。
  • 过早通过类型标注封闭表,之后却期望能添加字段。
  • 误以为使用 : 定义的方法会自动在整个类中共享精确的 self 类型。
  • 使用 :: 强制转换互不相关的类型,而不是修正根本的类型设计。
  • 构建不带判别字段的联合类型,导致下游难以细化类型。
  • 对 string & number 这类互不兼容的基本类型使用交叉类型。
  • 在仅涉及类型的任务中混入 Roblox 运行时架构指导。

示例

导出稳定的模块契约
--!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
使用泛型函数保留关系
--!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?
细化带标签的联合类型
--!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 的类对象式模块标注类型
--!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

评论

支持 Markdown