Typ Checking

*Dieser Inhalt wurde mit KI (Beta) übersetzt und kann Fehler enthalten. Um diese Seite auf Englisch zu sehen, klicke hier.

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.BrickColor
local 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 werden
local 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 = 1
local myString: string
myString = myNumber -- Nicht OK; Gib den Umwandlungsfehler ein
myString = myNumber :: any -- OK; alle Ausdrücke können auf "alle" gesendet werden
local 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) -> number
type 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)) -- 15
print(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 | string
type type1 = {foo: string}
type type2 = {bar: number}
type type1and2 = type1 & type2 -- :{foo: string} & {bar: number}
local numString1: numberOrString = true -- Typfehler
local 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()