Luau รองรับระบบประเภทอย่างค่อยเป็นค่อยไปผ่านการใช้การระบุประเภทและการอนุมาน ประเภทเหล่านี้ใช้เพื่อให้คำเตือน ข้อผิดพลาด และคำแนะนำที่ดีกว่าใน Script Editor
กำหนดประเภท
ใช้ type คำหลักเพื่อกำหนดประเภทของคุณเอง:
type Vector2 = {x: number, y: number}
โหมดการอนุมาน
มีโหมดการอนุมานประเภท Luau สามโหมดที่สามารถตั้งค่าได้ในบรรทัดแรกของ Script:
- --!nocheck — ไม่ตรวจสอบประเภท
- --!nonstrict — กำหนดประเภทตัวแปรเฉพาะเมื่อมีการระบุไว้อย่างชัดเจน
- --!strict — กำหนดประเภททั้งหมดตามประเภทที่อนุมานหรือระบุไว้อย่างชัดเจน
โหมด --!nonstrict และ --!strict ควบคุมว่าตัวตรวจสอบประเภทเข้มงวดเพียงใดในการอนุมานและตรวจสอบประเภทสำหรับตัวแปรและฟังก์ชัน การไม่ตรงกันของประเภทในสคริปต์จะเน้นใน Script Editor และแสดงเป็นคำเตือนในหน้าต่าง Script Analysis
ในการตั้งค่าโหมดเริ่มต้นสำหรับสคริปต์ทั้งหมดที่คุณสามารถเปลี่ยนแปลงตามต้องการ ให้ดูที่ Workspace.LuauTypeCheckMode
ประเภท
การระบุประเภทสามารถทำได้โดยใช้ : ตัวดำเนินการหลังจากตัวแปรท้องถิ่นจากนั้นตามด้วยการกำหนดประเภท โดยค่าเริ่มต้น ในโหมด nonstrict ตัวแปรทั้งหมดจะถูกกำหนดประเภทเป็น any
local foo: string = "bar"local x: number = 5
มีสี่ประเภทพื้นฐานที่สามารถใช้ในคำระบุประเภท:
- nil - ไม่มีค่า
- boolean - true หรือ false
- number - ค่าตัวเลข
- string - ข้อความ
ภายใน Roblox ทุกคลาส ประเภทข้อมูล และ enum จะมีประเภทของตนเองที่คุณสามารถตรวจสอบได้:
local somePart: Part = Instance.new("Part")local brickColor: BrickColor = somePart.BrickColorlocal material: Enum.Material = somePart.Material
หากต้องการทำให้ประเภทเป็นทางเลือก ให้ใช้ ? ที่ปลายของการระบุ:
local foo: string? = nil
สิ่งนี้จะทำให้ตัวแปรสามารถเป็นประเภทที่ระบุ (ในกรณีนี้คือ string) หรือ nil
ประเภทลิทเทอรัล
คุณยังสามารถแคสต์สตริงและบูลีนเป็นค่าลิทเทอรัลแทนที่จะใช้ string และ boolean:
local alwaysHelloWorld: "Hello world!" = "Hello world!"alwaysHelloWorld = "Just hello!" -- ข้อผิดพลาดประเภท: ประเภท '"Just hello!"' ไม่สามารถแปลงเป็น '"Hello world!"' ได้local alwaysTrue: true = false -- ข้อผิดพลาดประเภท: ประเภท 'false' ไม่สามารถแปลงเป็น 'true' ได้
การแคสต์ประเภท
บางครั้งคุณอาจต้องช่วยตัวตรวจสอบประเภทด้วยการแคสต์ค่าหนึ่งไปยังประเภทที่แตกต่างด้วย :: ตัวดำเนินการ:
local myNumber = 1local myString: stringmyString = myNumber -- ไม่ใช่ OK; ข้อผิดพลาดการแปลงประเภทmyString = myNumber :: any -- OK; การแสดงออกทั้งหมดสามารถแคสต์เป็น 'any'local myFlag = myNumber :: boolean -- ไม่ใช่ OK; ประเภทไม่เกี่ยวข้อง
การกำหนดประเภทฟังก์ชัน
พิจารณาฟังก์ชันต่อไปนี้:
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) -> numbertype 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}
Variadics
นี่คือฟังก์ชันที่คำนวณผลรวมของจำนวนใด ๆ :
local function addLotsOfNumbers(...)
local sum = 0
for _, v in {...} do
sum += v
end
return sum
end
ตามที่คาดไว้ ฟังก์ชันนี้สามารถรับค่าใด ๆ และตัวตรวจสอบประเภทจะไม่เกิดคำเตือนหากคุณจัด提供ประเภทที่ไม่ถูกต้อง เช่น string
print(addLotsOfNumbers(1, 2, 3, 4, 5)) -- 15print(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 | stringtype 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:
โมดูลประเภทใน ReplicatedStorageexport 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()