Luau supporta un sistema di tipo graduale attraverso l'uso di annotazioni di tipo e inferenze di tipo. Questi tipi vengono utilizzati per fornire avvertimenti, errori e suggerimenti migliori nell' Editor del Script.
Difinire un Type
Usa il type keyword per definire i tuoi tipi:
type Vector2 = {x: number, y: number}
Modalità di Inferenza
Ci sono tre modalità di inferenza Luau che possono essere impostate sulla prima riga di un Script :
- --!nocheck - Non controllare i tipi
- --!nonstrict - Modalità predefinita per tutti gli script, in cui si suppone che i tipi variabili siano esplicitamente annotati
- --!strict - Afferma tutti i tipi in base al inserisci / scriviimplicito o esplicitamente annotato
Il modo predefinito per il tipo checker è --!nonstrict . Gli altri due modi controllano quanto sia rigido il tipo checker con inferring e checker dei tipi per le variabili e le funzioni. Tutti i tipo mismatch in script sono evidenziati nell' Editor script e nella finestra di dialogo Script analysis.
Tipi
Un tipo di annotazione può essere definito utilizzando l'operatore : dopo una variabile locale, seguita da una definizione di tipo. Per impostazione predefinita, in nonstrict modalità, tutte le variabili sono assegnate il tipo any .
local foo: string = "bar"local x: number = 5
Ci sono quattro tipi primitivi che possono essere utilizzati in un'annotazione:
- nil - valore nullo
- boolean - true o false
- number - un valore numerico
- string - testo
All'interno di Roblox, tutte le Classi, i tipi di dati e gli enums hanno i loro tipi che puoi controllare contro:
local somePart: Part = Instance.new("Part")local brickColor: BrickColor = somePart.BrickColorlocal material: Enum.Material = somePart.Material
Per rendere un tipo opzionale, usa un ? alla fine dell'annotazione:
local foo: string? = nil
Questo consentirà alla variabile di essere o il tipo specificato (in questo caso string ) o nil .
Tipi letterali
Puoi anche convertire stringhe e booleani in valori letterali invece di utilizzare string e boolean :
local alwaysHelloWorld: "Hello world!" = "Hello world!"alwaysHelloWorld = "Just hello!" -- Tipo di errore: il tipo «Just hello!» non potrebbe essere convertito in «Hello Mondo!»local alwaysTrue: true = false -- Type error: Type 'false' could not be converted into 'true'
Tipi di cast
A volte, potrebbe essere necessario aiutare il tipochecker facendo esplicitamente in modo che un valore venga convertito in un altro tipo con l'operatore :: :
local myNumber = 1local myString: stringmyString = myNumber -- Not OK; tipo errore di conversionemyString = myNumber :: any -- OK; tutte le espressioni possono essere convertite in 'qualsiasi'local myFlag = myNumber :: boolean -- Not OK; types are unrelated
Tipo di funzione
Considera la seguente funzione:
local function add(x, y)
return x + y
end
Questa funzione aggiunge x a y , ma gli errori se uno o entrambi sono una Stringa. Luau non sa che questa funzione può utilizzare solo numeri. Per prevenire questa categoria di problema, aggiungi i tipi ai parametri:
local function add(x: number, y: number)
return x + y
end
Luau ora sa che la funzione prende due numeri e lancia un avvertimento se provi a passare qualcosa che non è un numero nella funzione:
add(5, 10)add(5, "foo") -- Type error: string could not be converted into number
Per definire un inserisci / scrividi ritorno, metti un operatore : alla fine della definizione della funzione:
local function add(x: number, y: number): number
Per restituire più tipi, inserisci i tipi in parentesi:
local function FindSource(script: BaseScript, pattern: string): (string, number)
return 42, true -- Tipi di errori
end
Difinire un tipo funzionale
Un tipo funzionale può essere definito utilizzando la sintassi (in) -> out . Utilizzando le funzioni dai precedenti esempi, i tipi delle funzioni sono:
type add = (x: number, y: number) -> numbertype FindSource = (script: BaseScript, pattern: string) -> (string, number)
Tipi di tavola
Luau non ha un inserisci / scrividi table , invece i tipi di tavola sono definiti utilizzando la sintassi {} . Un modo per definire le tavole è utilizzare la sintassi {type}, che definisce un inserisci / scrividi lista.
local numbers: {number} = {1, 2, 3, 4, 5}local characterParts: {Instance} = LocalPlayer.Character:GetChildren()
Definire i tipi di indice usando {[indexType]: valueType} :
local numberList: {[string]: number} = {Foo = 1,Baz = 10}numberList["bar"] = true -- Type error: boolean can't convert to number
Le tabelle possono anche avere stringenti indici di tipo definiti in un inserisci / scrivi.
type Car = {
Speed: number,
Drive: (Car) -> ()
}
local function drive(car)
-- Vai sempre al limite di velocità
end
local taxi: Car = {Speed = 30, Drive = drive}
Variadics
Ecco una funzione che calcola la somma di un numero arbitrario di numeri:
local function addLotsOfNumbers(...)
local sum = 0
for _, v in {...} do
sum += v
end
return sum
end
Come aspettato, questa funzione può prendere qualsiasi valore, e il tipochecker non mostrerà un avviso se fornisci un inserisci / scrivinon valido, come un string .
print(addLotsOfNumbers(1, 2, 3, 4, 5)) -- 15print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- Attempt to add string to number
Invece, assegna un tipo a ... , proprio come fai con qualsiasi altro inserisci / scrivi:
local function addLotsOfNumbers(...: number)
E ora, la seconda riga solleva un errore di tipo.
print(addLotsOfNumbers(1, 2, 3, 4, 5))print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- Tipo di errore: string non potrebbe essere convertito in numero
Tuttavia, questo non funziona quando si scrive una definizione di tipo funzionale:
type addLotsOfNumbers = (...: number) -> number -- Expected type, got ':'
Invece, usa la sintassi ...type per definire un inserisci / scrivivarietico.
type addLotsOfNumbers = (...number) -> number
Unioni e Intersezioni
Puoi persino definire un tipo come due o più tipi utilizzando un'unione o un intersezione:
type numberOrString = number | stringtype type1 = {foo: string}type type2 = {bar: number}type type1and2 = type1 & type2 -- :{foo: stringa} & {bar: number}local numString1: numberOrString = true -- Tipo di errorelocal numString2: type1and2 = {foo = "hello", bar = 1}
Difinire un tipo implicito
Puoi usare la funzione typeof in una definizione di tipo per i tipi inferred:
type Car = typeof({Speed = 0,Wheels = 4}) --> Car: {Speed: number, Wheels: number}
Un modo per utilizzare typeof è definire un tipo di metabelle usando setmetatable all'interno della funzione typeof :
type Vector = typeof(setmetatable({}::{x: number,y: number}, {}::{__add: (Vector, Vector|number) -> Vector}))-- Vector + Vector would return a Vector type
Generici
I generici sono parametri di base per i tipi. Considere il seguente oggetto State :
local State = {Key = "TimesClicked",Value = 0}
Senza generici, il tipo per questo oggetto sarebbe come segue:
type State = {Key: string,Value: number}
Tuttavia, potresti voler che il tipo per Value sia basato sul valore in arrivo, dove vengono inseriti i generici:
type GenericType<T> = T
Il <T> denota un tipo che può essere impostato su qualsiasi cosa. Il modo migliore per visualizzarlo è come un inserisci / scrividi sostituzione.
type List<T> = {T}local Names: List<string> = {"Bob", "Dan", "Mary"} -- Il tipo diventa {Stringa}local Fibonacci: List<number> = {1, 1, 2, 3, 5, 8, 13} -- Type becomes {number}
I generici possono anche avere più sostituzioni all'interno dei brackets.
type Map<K, V> = {[K]: V}
Per ricostruire l'oggetto State da prima, per utilizzare un inserisci / scrivigenerico:
type State<T> = {Key: string,Value: T}
Generici di funzione
Le funzioni possono anche utilizzare generici. L'esempio State inf inferisce il valore di T dai parametri in arrivo dalla funzione.
Per definire una funzione generica, aggiungi un <> a nome funzione:
local function State<T>(key: string, value: T): State<T>
return {
Key = key,
Value = value
}
end
local Activated = State("Activated", false) -- Stato<button>
local TimesClicked = State("TimesClicked", 0) -- State<number>
Tipo di esportazioni
Per rendere in modo che un tipo possa essere utilizzato al di fuori di un ModuleScript , usa il export keyword:
Tipi Modulo nel ReplicatedStorage
export type Cat = {Name: string,Meow: (Cat) -> ()}
Script che usa il modulo dei tipi
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()