型別檢查

*此內容是使用 AI(Beta 測試版)翻譯,可能含有錯誤。若要以英文檢視此頁面,請按一下這裡

Luau 支援透過型別註釋和型別推斷的漸進式型別系統。這些型別用於在 腳本編輯器 中提供更好的警告、錯誤和建議。

定義型別

使用 type 關鍵字來定義您自己的型別:


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

推斷模式

有三種 Luau 型別推斷模式可以在 Script 的第一行設定:

  • --!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 的一種方式是使用 setmetatable 定義元表型別,並將其放在 typeof 函數內:


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 關鍵字:

在 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} said meow`)
end
}
newCat:Meow()
©2026 Roblox Corporation、Roblox、Roblox 標誌及 Powering Imagination 是我們在美國及其他國家地區的部分註冊與未註冊商標。