類型檢查

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

Luau 透過使用類型標記和類型推論來支持逐漸類型系統。這些類型用於在 腳本編輯器 提供更好的警告、錯誤和建議。

定義類輸入

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


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

推論模式

有三種 Luau 類型推論模式可以在 Script 的第一行上設置:

  • --!nocheck — 不要檢查類型。
  • --!nonstrict — 只有在變量類型明確標示時才會宣稱變量類型。
  • --!strict — 檢查所有類型,基於引用或明確標示的輸入進行。

--!nonstrict--!strict 模式控制類型檢查器是否嚴格對變量和函數進行推論和檢查類型。在 腳本編輯器 中標示任何類型的不匹配,在 腳本分析窗口 中顯示警告。

類型

類型標記可以使用 : 操作符在本地變量之後定義,然後跟隨一個類型定義。預設情況下,在 nonstrict 模式下,所有變量都會被指派類型 any


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

有四種原始類型可以在注解中使用:

  • nil - 沒有值
  • boolean - true or false
  • 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!" -- 類型錯誤:「只是你好!」無法轉換為「你好世界!」
local alwaysTrue: true = false -- Type error: Type 'false' could not be converted into 'true'

類型投擲

有時候,您可能需要使用 :: 運作符明確將值轉換為不同類型的值來幫助類型檢查器:


local myNumber = 1
local myString: string
myString = myNumber -- 不支持;輸入轉換錯誤
myString = myNumber :: any -- 好;所有式子都可以投射到「任何」
local myFlag = myNumber :: boolean -- Not OK; types are unrelated

功能類型

考慮以下功能:


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") -- Type error: string could not be converted into number

要定義返回類輸入,請在函數定義的結尾放置 : 運作符:


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

要返回多種類型,請將類型放置在括號中:


local function FindSource(script: BaseScript, pattern: string): (string, number)
return 42, true -- 類型錯誤
end

定義功能類輸入

功能類型可以使用 syntax (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 error: boolean can't convert to number

表也可以在類輸入中定義明確的字串指數。


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)) -- Attempt to add string to number

取而代之,將類型指派給 ... , 就像你指派任何其他輸入一樣:


local function addLotsOfNumbers(...: number)

現在,第二行發出了類型錯誤。


print(addLotsOfNumbers(1, 2, 3, 4, 5))
print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- 類型錯誤:字串無法轉換為數字

但是,在寫功能類型定義時,這不會工作:


type addLotsOfNumbers = (...: number) -> number -- Expected type, got ':'

取而代之,使用 syntax ...type 來定義變異類輸入。


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

聯盟和交叉點

您甚至可以使用聯盟或交集來定義類型為兩種或更多種類型:


type numberOrString = number | string
type type1 = {foo: string}
type type2 = {bar: number}
type type1and2 = type1 & type2 -- {foo: 字串tring} 和 {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 would return a Vector type

一般化

一般字元是類型的基本參數參數。考慮以下 State 物件:


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

無法使用一般化,此對象的類型將如下:


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

然而,您可能希望類型 Value 基於收到的值來進行,這是 génériques 進入的地方:


type GenericType<T> = T

<T> 表示可以設為任何類型的類型。最好的方法是用作替換輸入來視覺化這一點。


type List<T> = {T}
local Names: List<string> = {"Bob", "Dan", "Mary"} -- 類型變為 {字串tring}
local Fibonacci: List<number> = {1, 1, 2, 3, 5, 8, 13} -- Type becomes {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) -- 狀態<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()