Luau mendukung sistem tipe bertahap melalui penggunaan anotasi tipe dan inferensi tipe. Tipe ini digunakan untuk memberikan peringatan, kesalahan, dan saran yang lebih baik di Editor Skrip.
Mendefinisikan tipe
Gunakan kata kunci type untuk mendefinisikan tipe Anda sendiri:
type Vector2 = {x: number, y: number}
Metode inferensi
Ada tiga metode inferensi tipe Luau yang dapat ditetapkan di baris pertama dari Script:
- --!nocheck — Jangan periksa tipe.
- --!nonstrict — Hanya memastikan tipe variabel jika mereka dianotasi secara eksplisit.
- --!strict — Memastikan semua tipe berdasarkan tipe yang diinfer atau dianotasi secara eksplisit.
Mode --!nonstrict dan --!strict mengendalikan seberapa ketat pemeriksa tipe dengan menginfer dan memeriksa tipe untuk variabel dan fungsi. Setiap ketidakcocokan tipe dalam skrip ditandai dalam Editor Skrip dan muncul sebagai peringatan di jendela Analisis Skrip.
Untuk menetapkan mode default untuk semua skrip yang dapat Anda ganti sesuai kebutuhan, lihat Workspace.LuauTypeCheckMode.
Tipe
Anotasi tipe dapat didefinisikan menggunakan operator : setelah variabel lokal, diikuti oleh definisi tipe. Secara default, dalam mode nonstrict, semua variabel diberikan tipe any.
local foo: string = "bar"local x: number = 5
Ada empat tipe primitif yang dapat digunakan dalam anotasi:
- nil - tidak ada nilai
- boolean - true atau false
- number - nilai numerik
- string - teks
Dalam Roblox, semua kelas, tipe data, dan enum memiliki tipe mereka sendiri yang dapat Anda periksa:
local somePart: Part = Instance.new("Part")local brickColor: BrickColor = somePart.BrickColorlocal material: Enum.Material = somePart.Material
Untuk membuat tipe opsional, gunakan ? di akhir anotasi:
local foo: string? = nil
Ini akan memungkinkan variabel menjadi tipe yang ditentukan (dalam hal ini string) atau nil.
Tipe literal
Anda juga dapat mengcasting string dan boolean menjadi nilai literal daripada menggunakan string dan boolean:
local alwaysHelloWorld: "Hello world!" = "Hello world!"alwaysHelloWorld = "Just hello!" -- Kesalahan tipe: Tipe '"Just hello!"' tidak dapat dikonversi menjadi '"Hello world!"'local alwaysTrue: true = false -- Kesalahan tipe: Tipe 'false' tidak dapat dikonversi menjadi 'true'
Casting tipe
Kadang-kadang, Anda mungkin perlu membantu pemeriksa tipe dengan mengcasting nilai secara eksplisit ke tipe yang berbeda menggunakan operator :::
local myNumber = 1local myString: stringmyString = myNumber -- Tidak OK; kesalahan konversi tipemyString = myNumber :: any -- OK; semua ekspresi dapat dicasting ke 'any'local myFlag = myNumber :: boolean -- Tidak OK; tipe tidak terkait
Pengetikan fungsi
Pertimbangkan fungsi berikut:
local function add(x, y)
return x + y
end
Fungsi ini menambahkan x ke y, tetapi menghasilkan kesalahan jika satu atau kedua dari mereka adalah string. Luau tidak tahu bahwa fungsi ini hanya dapat menggunakan angka. Untuk mencegah masalah kategori ini, tambahkan tipe pada parameter:
local function add(x: number, y: number)
return x + y
end
Luau sekarang tahu bahwa fungsi ini mengambil dua angka dan melempar peringatan jika Anda mencoba untuk memberikan sesuatu yang bukan angka ke fungsi:
add(5, 10)add(5, "foo") -- Kesalahan tipe: string tidak dapat dikonversi menjadi number
Untuk mendefinisikan tipe pengembalian, tempatkan operator : di akhir definisi fungsi:
local function add(x: number, y: number): number
Untuk mengembalikan beberapa tipe, tempatkan tipe dalam tanda kurung:
local function FindSource(script: BaseScript, pattern: string): (string, number)
return 42, true -- Kesalahan tipe
end
Mendefinisikan tipe fungsional
Tipe fungsional dapat didefinisikan dengan menggunakan sintaks (in) -> out. Menggunakan fungsi dari contoh sebelumnya, tipe dari fungsi adalah:
type add = (x: number, y: number) -> numbertype FindSource = (script: BaseScript, pattern: string) -> (string, number)
Tipe tabel
Luau tidak memiliki tipe table; sebaliknya, tipe tabel didefinisikan menggunakan sintaks {}. Salah satu cara untuk mendefinisikan tabel adalah menggunakan sintaks {type}, yang mendefinisikan tipe daftar.
local numbers: {number} = {1, 2, 3, 4, 5}local characterParts: {Instance} = LocalPlayer.Character:GetChildren()
Tentukan tipe indeks menggunakan {[indexType]: valueType}:
local numberList: {[string]: number} = {Foo = 1,Baz = 10}numberList["bar"] = true -- Kesalahan tipe: boolean tidak dapat dikonversi ke number
Tabel juga dapat memiliki indeks string eksplisit yang didefinisikan dalam tipe.
type Car = {
Speed: number,
Drive: (Car) -> ()
}
local function drive(car)
-- Selalu pergi sesuai batas kecepatan
end
local taxi: Car = {Speed = 30, Drive = drive}
Variadik
Ini adalah fungsi yang menghitung jumlah dari jumlah angka secara sewenang-wenang:
local function addLotsOfNumbers(...)
local sum = 0
for _, v in {...} do
sum += v
end
return sum
end
Seperti yang diharapkan, fungsi ini dapat menerima nilai apa pun, dan pemeriksa tipe tidak akan mengeluarkan peringatan jika Anda memberikan tipe yang tidak valid, seperti string.
print(addLotsOfNumbers(1, 2, 3, 4, 5)) -- 15print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- Mencoba menambahkan string ke number
Sebagai gantinya, tetapkan tipe ke ..., sama seperti cara Anda menetapkan tipe lainnya:
local function addLotsOfNumbers(...: number)
Dan sekarang, baris kedua menghasilkan kesalahan tipe.
print(addLotsOfNumbers(1, 2, 3, 4, 5))print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- Kesalahan tipe: string tidak dapat dikonversi menjadi number
Namun, ini tidak berfungsi saat menulis definisi tipe fungsional:
type addLotsOfNumbers = (...: number) -> number -- Tipe yang diharapkan, mendapat ':'
Sebagai gantinya, gunakan sintaks ...type untuk mendefinisikan tipe variadik.
type addLotsOfNumbers = (...number) -> number
Union dan intersection
Anda juga dapat mendefinisikan tipe sebagai dua atau lebih tipe menggunakan union atau intersection:
type numberOrString = number | stringtype type1 = {foo: string}type type2 = {bar: number}type type1and2 = type1 & type2 -- {foo: string} & {bar: number}local numString1: numberOrString = true -- Kesalahan tipelocal numString2: type1and2 = {foo = "hello", bar = 1}
Mendefiniskan tipe inferred
Anda dapat menggunakan fungsi typeof dalam definisi tipe untuk tipe inferred:
type Car = typeof({Speed = 0,Wheels = 4}) --> Car: {Speed: number, Wheels: number}
Salah satu cara menggunakan typeof adalah untuk mendefinisikan tipe metatable menggunakan setmetatable di dalam fungsi typeof:
type Vector = typeof(setmetatable({}::{x: number,y: number}, {}::{__add: (Vector, Vector|number) -> Vector}))-- Vector + Vector akan mengembalikan tipe Vector
Generik
Generik adalah pada tingkat dasar parameter untuk tipe. Pertimbangkan objek State berikut:
local State = {Key = "TimesClicked",Value = 0}
Tanpa generik, tipe untuk objek ini akan sebagai berikut:
type State = {Key: string,Value: number}
Namun, Anda mungkin ingin tipe untuk Value berdasarkan nilai yang masuk, yang di sinilah generik masuk:
type GenericType<T> = T
<T> menunjukkan tipe yang dapat diatur menjadi apa saja. Cara terbaik untuk memvisualisasikan ini adalah sebagai tipe substitusi.
type List<T> = {T}local Names: List<string> = {"Bob", "Dan", "Mary"} -- Tipe menjadi {string}local Fibonacci: List<number> = {1, 1, 2, 3, 5, 8, 13} -- Tipe menjadi {number}
Generik juga dapat memiliki beberapa substitusi di dalam tanda kurung.
type Map<K, V> = {[K]: V}
Untuk merombak objek State dari sebelumnya agar menggunakan tipe generik:
type State<T> = {Key: string,Value: T}
Generik fungsi
Fungsi juga dapat menggunakan generik. Contoh State menyimpulkan nilai dari T dari argumen yang masuk ke fungsi.
Untuk mendefinisikan fungsi generik, tambahkan <> ke nama fungsi:
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>
Ekspor tipe
Untuk membuat agar tipe dapat digunakan di luar ModuleScript, gunakan kata kunci export:
Modul Tipe di ReplicatedStorageexport type Cat = {Name: string,Meow: (Cat) -> ()}
Skrip Menggunakan Modul Tipe
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Types = require(ReplicatedStorage.Types)
local newCat: Types.Cat = {
Name = "metatablecat",
Meow = function(self)
print(`{self.Name} berkata meow`)
end
}
newCat:Meow()