Luau unterstützt ein graduelles Typ-System durch die Verwendung von Typ-Annotations und Typ-Inferenzen. Diese Arten werden verwendet, um bessere Warnungen, Fehler und Vorschläge im Skript-Editor zu liefern.
Typ definieren
Verwenden Sie das type Schlüsselwort, um Ihre eigenen Arten zu definieren:
type Vector2 = {x: number, y: number}
Ausfertigungsmodi
Es gibt drei Luau-Typ-Inferenzmodi, die auf der ersten Zeile eines Script festgelegt werden können:
- --!nocheck - Überprüfen Sie nicht die Typen
- --!nonstrict - Standardmodus für alle Skripte, nur behauptet variablen Typen, wenn sie explizit angegeben sind
- --!strict - Weist alle Arten basierend auf dem inferierten oder explizit annotierten eingeben
Der Standardmodus für den Typ-Checker ist --!nonstrict . Die anderen beiden Modi steuern, wie streng der Typ-Checker mit inferring und Check-Typen für Variablen und Funktionen ist. Alle Typ-Mismatches in Skripten werden im Skript-Editor und auf der Skript-Analyse-Registerkarte angezeigt.
Typen
Eine Typ-Annotation kann mit dem Operator : nach einer lokalen Variable definiert werden, gefolgt von einer Typ-Definition. Standardmäßig im nonstrict-Modus werden alle Variablen mit dem Typ any zugewiesen.
local foo: string = "bar"local x: number = 5
Es gibt vier primitivere Arten, die in einer Annotation verwendet werden können:
- nil - kein wert
- boolean - true oder false
- number - ein numerischer wert
- string - text
Innerhalb von Roblox haben alle Klassen, Datenarten und Enums eigene Arten, die Sie gegenüberchecken können:
local somePart: Part = Instance.new("Part")local brickColor: BrickColor = somePart.BrickColorlocal material: Enum.Material = somePart.Material
Um einen Typ optional zu machen, verwende ein ? am Ende der Annotierung:
local foo: string? = nil
Dies wird die Variable entweder als angegebten Typ (in diesem Fall string ) oder nil sein.
Buchstäbige Arten
Du kannst auch literale Werte anstelle von string und boolean verwenden:
local alwaysHelloWorld: "Hello world!" = "Hello world!"alwaysHelloWorld = "Just hello!" -- Typ error: Type „Hallo“ kann nicht in „Hallo, Welt“ umgewandelt werdenlocal alwaysTrue: true = false -- Type error: Type 'false' could not be converted into 'true'
Typen Casts
Manchmal müssen Sie dem Typchecker helfen, indem Sie einen Wert explizit mit einem anderen Typ mit dem :: Operator kasten:
local myNumber = 1local myString: stringmyString = myNumber -- Nicht OK; Gib den Umwandlungsfehler einmyString = myNumber :: any -- OK; alle Ausdrücke können auf "alle" gesendet werdenlocal myFlag = myNumber :: boolean -- Not OK; types are unrelated
Funktionstyp
Betrachte die folgende Funktion:
local function add(x, y)
return x + y
end
Diese Funktion fügt x zu y hinzu, aber Fehler, wenn einer oder beide von ihnen eine Stringsind. Luau weiß nicht, dass diese Funktion nur Zahlen verwenden kann. Um diese Kategorie von Problemen zu verhindern, füge Typen zu den Parametern hinzu:
local function add(x: number, y: number)
return x + y
end
Luau weiß jetzt, dass die Funktion zwei Zahlen erfordert und eine Warnung zurückgibt, wenn Sie versuchen, etwas, das kein Zahl ist, in die Funktion zu übergeben:
add(5, 10)add(5, "foo") -- Type error: string could not be converted into number
Um einen eingebenzu definieren, setzen Sie einen : Operator am Ende der Funktions definition:
local function add(x: number, y: number): number
Um mehrere Arten zurückzugeben, platzieren Sie die Arten in Klammern:
local function FindSource(script: BaseScript, pattern: string): (string, number)
return 42, true -- Typen Sie Fehler
end
Funktionstyp definieren
Ein funktionaler Typ kann durch die Verwendung der Syntax (in) -> out definiert werden. Mit der Verwendung der Funktionen aus den vorherigen Beispielen sind die Arten der Funktionen:
type add = (x: number, y: number) -> numbertype FindSource = (script: BaseScript, pattern: string) -> (string, number)
Tabelle Typen
Luau hat keinen table eingeben; stattdessen sind Tabeltyypen mit der {} Syntax definiert. Ein Weg, Tabelten zu definieren, ist die Verwendung der {type} Syntax, die eine eingebendefiniert.
local numbers: {number} = {1, 2, 3, 4, 5}local characterParts: {Instance} = LocalPlayer.Character:GetChildren()
Definieren Sie Index-Typen mit {[indexType]: valueType} :
local numberList: {[string]: number} = {Foo = 1,Baz = 10}numberList["bar"] = true -- Type error: boolean can't convert to number
Tabellen können auch explizite Strings-Indizes in einem eingebendefinieren.
type Car = {
Speed: number,
Drive: (Car) -> ()
}
local function drive(car)
-- Bleib immer bei der Geschwindigkeitsbegrenzung
end
local taxi: Car = {Speed = 30, Drive = drive}
Variadics
Hier ist eine Funktion, die die Summe einer beliebigen Anzahl von Zahlen berechnet:
local function addLotsOfNumbers(...)
local sum = 0
for _, v in {...} do
sum += v
end
return sum
end
Wie erwartet kann diese Funktion jeden Wert annehmen, und der Typchecker wird keine Warnung anzeigen, wenn Sie einen ungültigen eingebenangeben, z. B. eine string .
print(addLotsOfNumbers(1, 2, 3, 4, 5)) -- 15print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- Attempt to add string to number
Stattdessen weise einen Typ auf das ... , wie du einen anderen eingebenzuweist:
local function addLotsOfNumbers(...: number)
Und jetzt erhält die zweite Zeile einen Typfehler.
print(addLotsOfNumbers(1, 2, 3, 4, 5))print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- Typfehler: string konnte nicht in Zahl umgewandelt werden
Dies funktioniert jedoch nicht, wenn eine funktionale Typ- Definition aufgeschrieben wird:
type addLotsOfNumbers = (...: number) -> number -- Expected type, got ':'
Verwenden Sie stattdessen die Syntax ...type, um einen variadischen eingebenzu definieren.
type addLotsOfNumbers = (...number) -> number
Verbindungen und Intersections
Du kannst sogar einen Typ als zwei oder mehrere Arten definieren, indem du eine Union oder einen Intersektor verwendest:
type numberOrString = number | stringtype type1 = {foo: string}type type2 = {bar: number}type type1and2 = type1 & type2 -- :{foo: string} & {bar: number}local numString1: numberOrString = true -- Typfehlerlocal numString2: type1and2 = {foo = "hello", bar = 1}
Ein implizites Typ definieren
Du kannst die typeof Funktion in einer Typ- Definition für inferierte Arten verwenden:
type Car = typeof({Speed = 0,Wheels = 4}) --> Car: {Speed: number, Wheels: number}
Eine Möglichkeit, typeof zu verwenden, ist, einen Metatable-Typ zu definieren, der setmetatable innerhalb der Funktion typeof verwendet:
type Vector = typeof(setmetatable({}::{x: number,y: number}, {}::{__add: (Vector, Vector|number) -> Vector}))-- Vector + Vector would return a Vector type
Generika
Generics sind bei einem grundlegenden Niveau-Parameter für Typen. Betrachten Sie das folgende State Objekt:
local State = {Key = "TimesClicked",Value = 0}
Ohne Generika wäre der Typ für dieses Objekt wie folgt:
type State = {Key: string,Value: number}
Sie möchten jedoch den Typ für Value basieren auf dem eingehenden Wert, wo Generika kommen:
type GenericType<T> = T
Die <T> zeigt einen Typ, der auf alles eingestellt werden kann.Der beste Weg, dies zu visualisieren, ist als eingeben.
type List<T> = {T}local Names: List<string> = {"Bob", "Dan", "Mary"} -- Typ wird zu {String}local Fibonacci: List<number> = {1, 1, 2, 3, 5, 8, 13} -- Type becomes {number}
Generics können auch mehrere Ersetzungen innerhalb der Klammern haben.
type Map<K, V> = {[K]: V}
Um das State -Objekt zu ändern, um einen generischen eingebenzu verwenden:
type State<T> = {Key: string,Value: T}
Funktions-Generika
Funktionen können auch Generika verwenden. Das State Beispiel inferiert den Wert von T aus den Eingangsargumenten der Funktion.
Um eine generische Funktion zu definieren, füge einen <> zum Funktionsnamen hinzu:
local function State<T>(key: string, value: T): State<T>
return {
Key = key,
Value = value
}
end
local Activated = State("Activated", false) -- Zustand<button>
local TimesClicked = State("TimesClicked", 0) -- State<number>
Exporte tippen
Um es so zu machen, dass ein Typ außerhalb eines ModuleScript verwendet werden kann, verwenden Sie das export-Schlüsselwort:
Typen Sie Modul in ReplicatedStorage
export type Cat = {Name: string,Meow: (Cat) -> ()}
Script mit dem Typs-Modul
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()