关于 luau-type-expert
Luau Type Expert 是帮助开发者编写类型安全 Luau 代码的指导技能,尤其适用于启用严格检查的项目。它讲解类型语法、类型收窄、泛型、常见错误、Lint 规则和性能相关的类型实践。
主要功能
- 01讲解严格类型检查模式
- 02覆盖类型标注与类型别名
- 03指导类型收窄与类型转换
- 04介绍泛型和元表
- 05排查常见类型错误
- 06参考 Lint 与性能规则
适用场景
- 01在 Luau 文件中启用严格检查
- 02解决类型检查错误
- 03设计可复用的泛型类型
- 04依据 Lint 与性能模式审查代码
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ dig1t/ skills --skill luau-type-expert安装后在 Claude Code 中输入/luau-type-expert确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/api_reference.mdcommon-errors.mdlint-rules.mdperformance.md详细介绍
Luau 类型专家
提供专业指导,帮助编写类型安全、简洁且能通过严格类型检查的 Luau 代码。
类型模式
始终在文件顶部使用 --!strict。共有三种模式:
| 模式 | 行为 |
|---|---|
--!nocheck | 完全禁用类型检查 |
--!nonstrict | 未知类型会变为 any(默认) |
--!strict | 完整跟踪类型并捕获类型不匹配 |
语法要点
标准注解语法(变量、函数参数和返回值、可选类型 ?、多个返回值、可变参数、表类型、类型别名)见 references/api_reference.md。值得记住的部分:
-- Export for cross-module use
export type ItemRecord = { id: string, quantity: number }
-- Function type
type Callback = (player: Player, data: any) -> boolean
-- Generic aliases
type Result<T, E> = { ok: true, value: T } | { ok: false, error: E }
type Map<K, V> = { [K]: V }
-- Literal unions (discriminated)
type Status = "pending" | "active" | "completed"
-- Intersection: value has all these properties
type Person = Named & Aged
-- Function intersection (overloads)
type Stringify = ((n: number) -> string) & ((b: boolean) -> string)
类型收窄(细化)
Luau 会在条件代码块中通过 type()、typeof()(Roblox 实例)、真值判断和相等性检查来收窄类型:
local function process(value: string | number)
if type(value) == "string" then
print(value:upper()) -- value: string here
else
print(value + 1) -- value: number here
end
end
local function safePrint(msg: string?)
if msg then
print(msg) -- msg: string (not nil)
end
end
提前返回可保留类型细化:
local function requirePlayer(player: Player?): Player
if not player then
error("Player required")
end
-- player: Player (narrowed after early return)
return player
end
类型转换
使用 :: 覆盖推断类型:
-- Cast to specific type
local data = {} :: { string }
table.insert(data, "hello") -- OK
table.insert(data, 123) -- Error: number not string
-- Cast result of expression
local id = tostring(123) :: string
-- Cast for API returns
local part = workspace:FindFirstChild("Part") :: Part?
转换规则: 两个操作数中必须有一个是另一个的子类型,或者是 any。
泛型
-- Generic function
local function first<T>(arr: { T }): T?
return arr[1]
end
-- Generic with constraint
local function clone<T>(obj: T & {}): T
local copy = {}
for k, v in obj :: any do
copy[k] = v
end
return copy :: T
end
-- Generic type alias
type Container<T> = {
value: T,
set: (self: Container<T>, value: T) -> (),
get: (self: Container<T>) -> T,
}
-- Multiple type parameters
type Pair<K, V> = { key: K, value: V }
元表和面向对象编程
--!strict
export type Vector2 = {
x: number,
y: number,
}
type Vector2Impl = {
__index: Vector2Impl,
new: (x: number, y: number) -> Vector2,
add: (self: Vector2, other: Vector2) -> Vector2,
magnitude: (self: Vector2) -> number,
}
local Vector2: Vector2Impl = {} :: Vector2Impl
Vector2.__index = Vector2
function Vector2.new(x: number, y: number): Vector2
return setmetatable({ x = x, y = y }, Vector2) :: Vector2
end
function Vector2:add(other: Vector2): Vector2
return Vector2.new(self.x + other.x, self.y + other.y)
end
function Vector2:magnitude(): number
return math.sqrt(self.x^2 + self.y^2)
end
return Vector2
常见类型错误及修复方法
详细的错误解决方案见 references/common-errors.md。
快速修复:
| 错误 | 修复方法 |
|---|---|
Type 'X' could not be converted into 'Y' | 添加显式转换 :: Y 或修正类型 |
Unknown global 'X' | 导入模块或声明全局类型 |
Property 'X' is not compatible | 确保属性类型完全匹配 |
W_001: Unknown require | 使用正确的 require 路径别名 |
luau-lsp CLI 用法
# Basic analysis
luau-lsp analyze src/
# With sourcemap for Roblox
luau-lsp analyze --sourcemap=sourcemap.json src/
# With definitions
luau-lsp analyze --definitions:@roblox=globalTypes.d.luau src/
# Disable all FFlags
luau-lsp analyze --no-flags-enabled src/
.luaurc 配置
{
"languageMode": "strict",
"lint": {
"LocalShadow": "disabled",
"ImportUnused": "enabled"
},
"aliases": {
"@shared": "src/Shared",
"@server": "src/Server"
}
}
性能优化型类型写法
性能模式见 references/performance.md。
要点:
- 使用
table.field,而不是table["field"] - 保持元表层级浅(将
__index直接指向表) - 将内置函数设为局部变量:
local max = math.max - 避免使用
getfenv/setfenv(会导致去优化) - 对于已知大小的表,使用
table.create(n)
Lint 规则参考
所有 28 条 lint 规则见 references/lint-rules.md。
关键规则:
UnknownGlobal- 捕获拼写错误LocalUnused- 未使用的代码ImplicitReturn- 返回方式不一致UninitializedLocal- 赋值前使用
评论
支持 Markdown