Luau unterstützt ein graduelles Typensystem durch die Verwendung von Typ-Annotations und Typ-Behauptungen.Diese Arten werden verwendet, um bessere Warnungen, Fehler und Vorschläge im Skript-Editor bereitzustellen.
Definieren Sie einen eingeben
Verwende das type-Schlüsselwort, um deine eigenen Arten zu definieren:
type Vector2 = {x: number, y: number}
Schlussfolgerungsmodi
Es gibt drei Luau-Typ-Inferenzmodi, die auf der ersten Zeile eines Script festgelegt werden können:
- --!nocheck — Überprüfe keine Arten.
- --!nonstrict — Behauptet nur Variantentypen, wenn sie explizit angezeichnet sind.
- --!strict — Behauptet alle Arten basierend auf dem abgeleiteten oder explizit angegebenen eingeben.
Die --!nonstrict- und --!strict-Modi steuern, wie streng der Typenprüfer bei der Inferenz und Überprüfung von Typen für Variablen und Funktionen ist.Alle Arten von Fehlern in Skripten werden im Skript-Editor hervorgehoben und als Warnungen im Skript-Analyse-Fenster angezeigt.
Arten
Eine Typ-Annotation kann mit dem Operator : nach einer lokalen Variable definiert werden, gefolgt von einer Typ-Definition.Standardmäßig, im Modus nonstrict , werden alle Variablen dem Typ any zugewiesen.
local foo: string = "bar"local x: number = 5
Es gibt vier primitive Arten, die in einer Annotation verwendet werden können:
- nil - kein wert
- boolean - true or false
- number - ein numerischer wert
- string - text
Innerhalb von Roblox haben alle Klassen, Datenformate und Enums eigene Arten, gegen die Sie überprüfen 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 Anmerkung:
local foo: string? = nil
Dies wird es der Variable ermöglichen, entweder der angegebenen Art zu sein (in diesem Fall string ) oder nil .
Literal-Typen
Du kannst auch Zeichenketten und Booleen zu literalen Werten ausgeben, anstatt string und boolean zu verwenden:
local alwaysHelloWorld: "Hello world!" = "Hello world!"alwaysHelloWorld = "Just hello!" -- Fehlertyp: Der Fehlertyp 'Just hello!' konnte nicht in 'Hallo Welt!' umgewandelt werdenlocal alwaysTrue: true = false -- Type error: Type 'false' could not be converted into 'true'
Typ-Castings
Manchmal müssen Sie den Typprüfer möglicherweise unterstützen, indem Sie einen Wert explizit auf einen anderen Typ mit dem :: Operator kastrieren:
local myNumber = 1local myString: stringmyString = myNumber -- Nicht in Ordnung; Art der Umwandlungsfehler eingebenmyString = myNumber :: any -- OK; alle Ausdrücke können auf 'any' gecastet werdenlocal myFlag = myNumber :: boolean -- Not OK; types are unrelated
Funktionentypisierung
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 sind eine String.Luau weiß nicht, dass diese Funktion nur Zahlen verwenden kann.Um diese Kategorie von Problemen zu verhindern, füge Arten zu den Parametern hinzu:
local function add(x: number, y: number)
return x + y
end
Luau weiß jetzt, dass die Funktion zwei Zahlen verwendet und eine Warnung ausgibt, wenn du versuchst, irgendetwas, das keine 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, stelle einen : -Operator am Ende der Funktions definition ein:
local function add(x: number, y: number): number
Um mehrere Arten zurückzugeben, stelle die Arten in Klammern dar:
local function FindSource(script: BaseScript, pattern: string): (string, number)
return 42, true -- Fehler eingeben
end
Definiere einen funktionalen eingeben
Ein funktionaler Typ kann durch die Syntax (in) -> out definiert werden. Mit den Funktionen aus den vorherigen Beispielen sind die Arten der Funktionen:
type add = (x: number, y: number) -> numbertype FindSource = (script: BaseScript, pattern: string) -> (string, number)
Tabellenarten
Luau hat keinen table eingeben; stattdessen werden Tabellenarten mit {} Syntax definiert.Eine Möglichkeit, Tabellen zu definieren, ist die Verwendung der {type}-Syntax, die einen Listen eingebendefiniert.
local numbers: {number} = {1, 2, 3, 4, 5}local characterParts: {Instance} = LocalPlayer.Character:GetChildren()
Definieren Sie Indexarten 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 Zeichenindizes haben, die in einem eingebendefiniert sind.
type Car = {
Speed: number,
Drive: (Car) -> ()
}
local function drive(car)
-- Gehen Sie immer das Geschwindigkeitslimit
end
local taxi: Car = {Speed = 30, Drive = drive}
Variatiken
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 Typprüfer wird keine Warnung auslösen, wenn du einen ungültigen eingebenlieferst, wie z. B. 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 die ... zu, genau wie du einen anderen eingebenzuordnest:
local function addLotsOfNumbers(...: number)
Und jetzt erhebt die zweite Zeile einen Typfehler.
print(addLotsOfNumbers(1, 2, 3, 4, 5))print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- Fehlertyp: Zeichenkette konnte nicht in Zahl umgewandelt werden
Dies funktioniert jedoch nicht, wenn du eine funktionale Typdefinition schreibst:
type addLotsOfNumbers = (...: number) -> number -- Expected type, got ':'
Verwende stattdessen die Syntax ...type, um einen variablen eingebenzu definieren.
type addLotsOfNumbers = (...number) -> number
Verbindungen und Kreuzungen
Du kannst sogar einen Typ definieren, als zwei oder mehrere Arten mit einer Union oder Intersektion:
type numberOrString = number | stringtype type1 = {foo: string}type type2 = {bar: number}type type1and2 = type1 & type2 -- {foo: string} & {bar: number}local numString1: numberOrString = true -- Fehlertyplocal numString2: type1and2 = {foo = "hello", bar = 1}
Definieren Sie einen abgeleiteten eingeben
Du kannst die typeof-Funktion in einer Typdefinition für abgeleitete Arten verwenden:
type Car = typeof({Speed = 0,Wheels = 4}) --> Car: {Speed: number, Wheels: number}
Eine Möglichkeit, typeof zu verwenden, besteht darin, einen metastierbaren Typ mit setmetatable innerhalb der typeof-Funktion zu definieren:
type Vector = typeof(setmetatable({}::{x: number,y: number}, {}::{__add: (Vector, Vector|number) -> Vector}))-- Vector + Vector would return a Vector type
Generische
Generika sind auf einer grundlegenden Ebene-Paramètres für Arten. Betrachten Sie das folgende State Objekt:
local State = {Key = "TimesClicked",Value = 0}
Ohne Generics wäre der Typ für dieses Objekt wie folgt:
type State = {Key: string,Value: number}
Sie möchten jedoch, dass der Typ für Value auf den eingehenden Wert basiert, wo Generatoren ins Spiel kommen:
type GenericType<T> = T
Die <T> zeigt einen Typ an, der auf alles gesetzt werden kann. Die beste Art, dies visuell darzustellen, 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}
Generika können auch mehrere Substitutionen innerhalb der Klammern haben.
type Map<K, V> = {[K]: V}
Um das State Objekt von früher neu zu verwenden, um einen generischen eingebenzu verwenden:
type State<T> = {Key: string,Value: T}
Funktionsgenerika
Funktionen können auch Generika verwenden. Das State Beispiel schließt den Wert von T aus den eingehenden Argumenten der Funktion ab.
Um eine generische Funktion zu definieren, füge ein <> 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<bool>
local TimesClicked = State("TimesClicked", 0) -- State<number>
Typ-Ausgaben
Um das so zu machen, dass ein Typ außerhalb einer ModuleScript verwendet werden kann, verwende das Schlüsselwort export:
Typenmodul in ReplicatedStorage
export type Cat = {Name: string,Meow: (Cat) -> ()}
Skript mit dem Typenmodul verwenden
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()