Luau wspiera system typów poprzez użycie anotacji typu i innych wskazań typu. Te rodzaje są używane do dostarczania lepszych ostrzeżeń, błędów i sugestii w 編輯器脚本.
Definiowanie typu
Użyj type słowa kluczowego, aby zdefiniować własne rodzaje:
type Vector2 = {x: number, y: number}
Tryby wykładni
Są trzy tryby luau do wykrywania, które można ustawić na pierwszej linii Script :
- --!nocheck - Nie sprawdzać typów
- --!nonstrict - Domyślny tryb dla wszystkich skryptów, tylko potwierdza zmienne typy, jeśli są wyraźnie zapisane
- --!strict - Asseruje wszystkie rodzaje w oparciu o wskazany lub wyraźnie anotowany wpisywać
Domyślnym modelem dla weryfikatora typu jest --!nonstrict. Modele dwie kontrolują, jak rygorystyczny jest weryfikator typu z weryfikacją i sprawdzaniem typów dla zmiennej i funkcji. Każde niezgadzanie w skryptach jest podświetlone w edytorze scriptów i powoduje powstawanie ostrzeżeń w okienku analizy scriptów.
Typy
Anotacja typu może być zdefiniowana używając operatora : po zmiennej lokalnej, następnie definicji typu. Domyślnie w trybie nonstrict wszystkie zmienne są przypisane typowi any.
local foo: string = "bar"local x: number = 5
Są cztery podstawowe rodzaje, które można użyć w anotacji:
- nil - bez wartości
- boolean - true lub false
- number - liczbową wartość
- string - tekst
W Roblox wszystkie klasy, rodzaje danych i ennumy mają własne rodzaje, które możesz sprawdzić przeciwko:
local somePart: Part = Instance.new("Part")local brickColor: BrickColor = somePart.BrickColorlocal material: Enum.Material = somePart.Material
Aby uczynić typ opcjonalny, użyj ? na końcu anotacji:
local foo: string? = nil
Pozwoli to zmienne być albo string lub nil w tym przypadku.
Typy litery
Możesz również używać string i boolean zamiast użyć string i 1>button1>:
local alwaysHelloWorld: "Hello world!" = "Hello world!"alwaysHelloWorld = "Just hello!" -- Typ błędu: Typ „Just hello!” nie może zostać przetłumaczony na „Hello world!”local alwaysTrue: true = false -- Type error: Type 'false' could not be converted into 'true'
Typy rzucane
Czasami możliwe, że będziesz musiał pomóc weryfikatorowi poprawności poprzez wyraźne przekazanie wartości na inny typ z użyciem operтора :: :
local myNumber = 1local myString: stringmyString = myNumber -- Nie OK; wpisz błąd konwersjimyString = myNumber :: any -- OK; wszystkie wyrażenia można zastosować do "dowolnego"local myFlag = myNumber :: boolean -- Not OK; types are unrelated
Typowanie funkcji
Zastanów się nad następującą funkcją:
local function add(x, y)
return x + y
end
Funkcja ta dodaje x do y, ale błędy, jeśli jeden lub oba są ciąg. Luau nie wie, że ta funkcja może używać tylko liczb. Aby zapobiec tej kategorii problemu, dodaj typy do parametrów:
local function add(x: number, y: number)
return x + y
end
Luau teraz wie, że funkcja wymaga dwóch liczb i wyrzuca ostrzeżenie, jeśli spróbujesz przesłać coś, co nie jest liczbą do funkcji:
add(5, 10)add(5, "foo") -- Type error: string could not be converted into number
Aby zdefiniować wpisywaćzwrotu, umieść operator : na końcu definicji funkcji:
local function add(x: number, y: number): number
Aby zwrócić wiele rodzajów, umieść rodzaje w nawiasach:
local function FindSource(script: BaseScript, pattern: string): (string, number)
return 42, true -- Błędy wpisywania
end
Definowanie funkcjonalnego typu
Funkcjonalny typ można zdefiniować poprzez użycie struktury (in) -> out. Używając funkcji z poprzednich przykładów, rodzaje funkcji są następujące:
type add = (x: number, y: number) -> numbertype FindSource = (script: BaseScript, pattern: string) -> (string, number)
Typy tabel
Luau nie ma table wpisywać; zamiast tego, typy tabel są zdefiniowane używając {} sintetyki. Jeden z sposobów zdefiniowania tabel jest używanie sintetyki {type}, która zdefiniuje wpisywaćlisty.
local numbers: {number} = {1, 2, 3, 4, 5}local characterParts: {Instance} = LocalPlayer.Character:GetChildren()
Definiuj rodzaje wskaźników używając {[indexType]: valueType} :
local numberList: {[string]: number} = {Foo = 1,Baz = 10}numberList["bar"] = true -- Type error: boolean can't convert to number
Tabela może również mieć wyraźnie zdefiniowane wskaźniki strun w wpisywać.
type Car = {
Speed: number,
Drive: (Car) -> ()
}
local function drive(car)
-- Zawsze przekrocz limit prędkości
end
local taxi: Car = {Speed = 30, Drive = drive}
Zróżnicowane
Oto funkcja, która oblicza sumę dowolnej liczby:
local function addLotsOfNumbers(...)
local sum = 0
for _, v in {...} do
sum += v
end
return sum
end
Oczekiwanie, że ta funkcja może przyjąć dowolną wartość, a typ sprawdzać nie będzie ostrzeżenie, jeśli zaoferujesz nieprawidłowy wpisywać, takich jak string .
print(addLotsOfNumbers(1, 2, 3, 4, 5)) -- 15print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- Attempt to add string to number
Zamiast tego przypisz typ ... , tak jak przydzielasz dowolny inny wpisywać:
local function addLotsOfNumbers(...: number)
A teraz druga linia weryfikuje błąd typu.
print(addLotsOfNumbers(1, 2, 3, 4, 5))print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- Błąd w przetwarzaniu: strona nie mogła być przekonwertowana na liczbę
Jednak nie działa to, gdy piszesz definicję funkcjonalnego typu:
type addLotsOfNumbers = (...: number) -> number -- Expected type, got ':'
Zamiast tego użyj ...type Syntaxy, aby zdefiniować wpisywaćwieloznaczne.
type addLotsOfNumbers = (...number) -> number
Związki i intersekcje
Możesz nawet zdefiniować typ jako dwa lub więcej typów używając unii lub intersekcji:
type numberOrString = number | stringtype type1 = {foo: string}type type2 = {bar: number}type type1and2 = type1 & type2 -- :{foo: ciąg} & {bar: number}local numString1: numberOrString = true -- Błąd wpisulocal numString2: type1and2 = {foo = "hello", bar = 1}
Definiowanie ukrytego typu
Możesz użyć funkcji typeof w definicji typu dla wskazanych typów:
type Car = typeof({Speed = 0,Wheels = 4}) --> Car: {Speed: number, Wheels: number}
Jednym z sposobów użycia typeof jest zdefiniowanie metabeli setmetatable w funkcji typeof w następujący sposób:
type Vector = typeof(setmetatable({}::{x: number,y: number}, {}::{__add: (Vector, Vector|number) -> Vector}))-- Vector + Vector would return a Vector type
Generika
Generatory są podstawowymi parametrami poziomu dla typów. Rozważaj następujące State obiekt:
local State = {Key = "TimesClicked",Value = 0}
Bez generików, typ dla tego obiektu będzie następujący:
type State = {Key: string,Value: number}
Jednak możesz chcieć, aby typ dla Value opierał się na wartości, która jest źródłem generycznych:
type GenericType<T> = T
Ten znak <T> określa typ, który można ustawić na wszystko.Najlepszym sposobem na wizualizację tego jest jako wpisywaćzastępczy.
type List<T> = {T}local Names: List<string> = {"Bob", "Dan", "Mary"} -- Typ staje się {ciąg}local Fibonacci: List<number> = {1, 1, 2, 3, 5, 8, 13} -- Type becomes {number}
Generics mogą również mieć wiele zastępcze w środku nawiasów.
type Map<K, V> = {[K]: V}
Aby ponownie zaimportować obiekt State z poprzedniego użycia, aby użyć generycznego wpisywać:
type State<T> = {Key: string,Value: T}
Generika funkcji
Funkcje mogą również używać generików. Przykład State oznacza wartość T z argumentów funkcji.
Aby zdefiniować genériczną funkcję, dodaj <> do nazwy funkcji:
local function State<T>(key: string, value: T): State<T>
return {
Key = key,
Value = value
}
end
local Activated = State("Activated", false) -- Stan<button>
local TimesClicked = State("TimesClicked", 0) -- State<number>
Eksportuj typy
Aby umożliwić użycie typu poza ModuleScript, użyj słowa kluczowego export :
Typy modułu w ReplicatedStorage
export type Cat = {Name: string,Meow: (Cat) -> ()}
Skrypt korzystający z modułu typów
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()