类型检查

*此内容使用人工智能(Beta)翻译,可能包含错误。若要查看英文页面,请点按 此处

Luau 支持通过使用类型注解和类型推断来实现渐进式类型系统。这些类型用于在 脚本编辑器 中提供更好的警告、错误和建议。

定义类型

使用 type 关键字定义您自己的类型:


type Vector2 = {x: number, y: number}

推断模式

Script 的第一行可以设置三种 Luau 类型推断模式:

  • --!nocheck — 不检查类型。
  • --!nonstrict — 仅在显式注解的情况下断言变量类型。
  • --!strict — 根据推断或显式注解的类型断言所有类型。

--!nonstrict--!strict 模式控制类型检查器对变量和函数的推断和检查类型的严格程度。脚本中的任何类型不匹配都会在 脚本编辑器 中突出显示,并在 脚本分析 窗口中显示为警告。

要为所有脚本设置默认模式,您可以根据需要覆盖,请参见 Workspace.LuauTypeCheckMode

类型

类型注解可以使用 : 运算符在局部变量后定义,后面跟着类型定义。默认情况下,在 nonstrict 模式下,所有变量的类型都被指定为 any


local foo: string = "bar"
local x: number = 5

可以在注解中使用四种原始类型:

  • nil - 无值
  • boolean - truefalse
  • number - 一个数值
  • string - 文本

在 Roblox 中,所有类、数据类型和枚举都有各自的类型,您可以根据这些类型进行检查:


local somePart: Part = Instance.new("Part")
local brickColor: BrickColor = somePart.BrickColor
local material: Enum.Material = somePart.Material

要使类型可选,请在注释的末尾使用 ?


local foo: string? = nil

这将允许变量既可以是指定类型(在本例中为 string),又可以是 nil

字面值类型

您还可以将字符串和布尔值转换为字面值,而不是使用 stringboolean


local alwaysHelloWorld: "Hello world!" = "Hello world!"
alwaysHelloWorld = "Just hello!" -- 类型错误:类型 '"Just hello!"' 无法转化为 '"Hello world!"'
local alwaysTrue: true = false -- 类型错误:类型 'false' 无法转化为 'true'

类型转换

有时,您可能需要通过使用 :: 运算符明确地将值转换为不同的类型来帮助类型检查器:


local myNumber = 1
local myString: string
myString = myNumber -- 不可;类型转换错误
myString = myNumber :: any -- 可以;所有表达式都可以转换为 'any'
local myFlag = myNumber :: boolean -- 不可;类型不相关

函数类型

考虑以下函数:


local function add(x, y)
return x + y
end

这个函数将 x 加到 y 上,但如果其中一个或两个是字符串,就会出错。Luau 并不知道这个函数只能使用数字。为了防止这种问题,给参数添加类型:


local function add(x: number, y: number)
return x + y
end

Luau 现在知道这个函数接受两个数字,如果您尝试传递任何不是数字的内容,将抛出警告:


add(5, 10)
add(5, "foo") -- 类型错误:字符串无法转化为数字

要定义返回类型,请在函数定义末尾加上 : 运算符:


local function add(x: number, y: number): number

要返回多个类型,请将类型放在括号中:


local function FindSource(script: BaseScript, pattern: string): (string, number)
return 42, true -- 类型错误
end

定义函数类型

函数类型可以使用语法 (in) -> out 定义。使用前面示例中的函数,其类型为:


type add = (x: number, y: number) -> number
type FindSource = (script: BaseScript, pattern: string) -> (string, number)

表类型

Luau 没有 table 类型;相反,表类型使用 {} 语法定义。定义表的一种方法是使用 {type} 语法,它定义了列表类型。


local numbers: {number} = {1, 2, 3, 4, 5}
local characterParts: {Instance} = LocalPlayer.Character:GetChildren()

使用 {[indexType]: valueType} 定义索引类型:


local numberList: {[string]: number} = {
Foo = 1,
Baz = 10
}
numberList["bar"] = true -- 类型错误:布尔值无法转化为数字

表也可以在类型中定义明确的字符串索引。


type Car = {
Speed: number,
Drive: (Car) -> ()
}
local function drive(car)
-- 始终遵循限速
end
local taxi: Car = {Speed = 30, Drive = drive}

可变参数

这是一个计算任意数量数字总和的函数:


local function addLotsOfNumbers(...)
local sum = 0
for _, v in {...} do
sum += v
end
return sum
end

正如预期的那样,这个函数可以接受任何值,如果您提供无效类型,例如 string,类型检查器将不会引发警告。


print(addLotsOfNumbers(1, 2, 3, 4, 5)) -- 15
print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- 尝试将字符串添加到数字

相反,为 ... 分配一个类型,就像为任何其他类型分配一样:


local function addLotsOfNumbers(...: number)

现在,第二行将引发类型错误。


print(addLotsOfNumbers(1, 2, 3, 4, 5))
print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- 类型错误:字符串无法转化为数字

但是,当编写函数类型定义时,这样做是无效的:


type addLotsOfNumbers = (...: number) -> number -- 预期的类型,得到 ':'

相反,使用语法 ...type 定义可变参数类型。


type addLotsOfNumbers = (...number) -> number

联合和交叉类型

您甚至可以将类型定义为两种或多种类型的联合或交叉:


type numberOrString = number | string
type type1 = {foo: string}
type type2 = {bar: number}
type type1and2 = type1 & type2 -- {foo: string} & {bar: number}
local numString1: numberOrString = true -- 类型错误
local numString2: type1and2 = {foo = "hello", bar = 1}

定义推断类型

您可以在类型定义中使用 typeof 函数以获取推断类型:


type Car = typeof({
Speed = 0,
Wheels = 4
}) --> Car: {Speed: number, Wheels: number}

使用 typeof 的一种方法是通过在 typeof 函数中使用 setmetatable 来定义元表类型:


type Vector = typeof(setmetatable({}::{
x: number,
y: number
}, {}::{
__add: (Vector, Vector|number) -> Vector
}))
-- Vector + Vector 将返回 Vector 类型

泛型

泛型在基本层面上是类型的参数。考虑以下 State 对象:


local State = {
Key = "TimesClicked",
Value = 0
}

没有泛型的情况下,该对象的类型如下:


type State = {
Key: string,
Value: number
}

然而,您可能希望 Value 的类型基于传入的值,这就是泛型的用武之地:


type GenericType<T> = T

<T> 表示可以设置为任何内容的类型。将其可视化的最佳方法是作为替代类型。


type List<T> = {T}
local Names: List<string> = {"Bob", "Dan", "Mary"} -- 类型变为 {string}
local Fibonacci: List<number> = {1, 1, 2, 3, 5, 8, 13} -- 类型变为 {number}

泛型也可以在方括号中具有多个替代。


type Map<K, V> = {[K]: V}

要将之前的 State 对象重新构建为使用泛型类型:


type State<T> = {
Key: string,
Value: T
}

函数泛型

函数也可以使用泛型。State 示例从函数传入的参数推断 T 的值。

要定义一个泛型函数,在函数名称后添加 <>


local function State<T>(key: string, value: T): State<T>
return {
Key = key,
Value = value
}
end
local Activated = State("Activated", false) -- State<boolean>
local TimesClicked = State("TimesClicked", 0) -- State<number>

类型导出

要使类型可以在 ModuleScript 之外使用,请使用 export 关键字:

Types Module in ReplicatedStorage

export type Cat = {
Name: string,
Meow: (Cat) -> ()
}
使用类型模块的脚本

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Types = require(ReplicatedStorage.Types)
local newCat: Types.Cat = {
Name = "metatablecat",
Meow = function(self)
print(`{self.Name} 说喵`)
end
}
newCat:Meow()
©2026 Roblox Corporation、Roblox、Roblox 标志及 Powering Imagination 是我们在美国及其他国家或地区的注册与未注册商标。