Controllo del tipo

*Questo contenuto è tradotto usando AI (Beta) e potrebbe contenere errori. Per visualizzare questa pagina in inglese, clicca qui.

Luau supporta un sistema di tipo graduale attraverso l'uso di annotazioni di tipo e inferenza di tipo.Questi tipi vengono utilizzati per fornire avvertimenti, errori e suggerimenti migliori nell'Editor di script.

Definisci un inserisci / scrivi

Usa la parola chiave type per definire i tuoi tipi:


type Vector2 = {x: number, y: number}

Modalità di inferenza

Ci sono tre modi di inferenza di tipo Luau che possono essere impostati sulla prima linea di un Script :

  • --!nocheck — Non controllare i tipi.
  • --!nonstrict — Assicura solo i tipi di variabili se sono esplicitamente annotati.
  • --!strict — Afferma tutti i tipi in base al inserisci / scriviinferito o esplicitamente annotato.

I modi --!nonstrict e --!strict controllano quanto è rigoroso il controllo del tipo con l'inferenza e il controllo dei tipi per le variabili e le funzioni.Qualsiasi tipo di incoerenza negli script viene evidenziato nell' Editor di script e viene visualizzato come avvertimento nella finestra Analisi degli script.

Tipi

Una annotazione di tipo può essere definita utilizzando l'operatore : dopo una variabile locale, seguito da una definizione di tipo.Per impostazione predefinita, in modalità nonstrict , tutte le variabili vengono 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 - nessun valore
  • boolean - true or false
  • number - un valore numerico
  • string - testo

All'interno di Roblox, tutte le Classi, i tipi di dati e gli enums hanno i propri tipi che puoi controllare:


local somePart: Part = Instance.new("Part")
local brickColor: BrickColor = somePart.BrickColor
local material: Enum.Material = somePart.Material

Per rendere un tipo opzionale, usa un ? alla fine dell'annotazione:


local foo: string? = nil

Ciò consentirà alla variabile di essere o il tipo specificato (in questo caso string ) o nil .

Tipi letterali

Puoi anche castare stringhe e booleani a valori letterali invece di usare string e boolean :


local alwaysHelloWorld: "Hello world!" = "Hello world!"
alwaysHelloWorld = "Just hello!" -- Errore di tipo: il tipo 'Just hello!' non è stato convertito in 'Hello Mondo!'
local alwaysTrue: true = false -- Type error: Type 'false' could not be converted into 'true'

Tipi di cast

A volte, potresti aver bisogno di aiutare il controllore di tipo a esprimere esplicitamente un valore a un diverso tipo con l'operatore :::


local myNumber = 1
local myString: string
myString = myNumber -- Non OK; tipo errore di conversione
myString = myNumber :: any -- OK; tutte le espressioni possono essere castate a 'qualsiasi'
local myFlag = myNumber :: boolean -- Not OK; types are unrelated

Tipizzazione della funzione

Considera la seguente funzione:


local function add(x, y)
return x + y
end

Questa funzione aggiunge x a y, ma 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 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 avviso se tenti di 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, posiziona i tipi tra parentesi:


local function FindSource(script: BaseScript, pattern: string): (string, number)
return 42, true -- Errori di tipo
end

Definisci un inserisci / scrivifunzionale

Un tipo funzionale può essere definito utilizzando la sintassi (in) -> out . Utilizzando le funzioni degli esempi precedenti, i tipi delle funzioni sono:


type add = (x: number, y: number) -> number
type FindSource = (script: BaseScript, pattern: string) -> (string, number)

Tipi di tabelle

Luau non ha un inserisci / scrivitable ; invece, i tipi di tabella sono definiti utilizzando la sintassi {}.Un modo per definire le tabelle è utilizzare la sintassi {type}, che definisce un inserisci / scrividi elenco.


local numbers: {number} = {1, 2, 3, 4, 5}
local characterParts: {Instance} = LocalPlayer.Character:GetChildren()

Definisci 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 indici di stringa espliciti 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}

Variadici

Ecco una funzione che calcola la somma di una qualsiasi quantità di numeri:


local function addLotsOfNumbers(...)
local sum = 0
for _, v in {...} do
sum += v
end
return sum
end

Come previsto, questa funzione può prendere qualsiasi valore, e il controllore di tipo non solleverà un avviso se fornisci un inserisci / scrivinon valido, come un string .


print(addLotsOfNumbers(1, 2, 3, 4, 5)) -- 15
print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- Attempt to add string to number

Invece, assegna un tipo al ..., proprio come quando assegni qualsiasi altro inserisci / scrivi:


local function addLotsOfNumbers(...: number)

E ora, la seconda linea solleva un errore di tipo.


print(addLotsOfNumbers(1, 2, 3, 4, 5))
print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- Errore di tipo: la stringa non è stata convertita 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 / scrivivariabile.


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 | string
type type1 = {foo: string}
type type2 = {bar: number}
type type1and2 = type1 & type2 -- {foo: stringa} e {bar: number}
local numString1: numberOrString = true -- Errore di tipo
local numString2: type1and2 = {foo = "hello", bar = 1}

Definisci un inserisci / scriviinferito

Puoi usare la funzione typeof in una definizione di tipo per i tipi inferiti:


type Car = typeof({
Speed = 0,
Wheels = 4
}) --> Car: {Speed: number, Wheels: number}

Un modo per utilizzare typeof è definire un tipo metatable utilizzando 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 livello di base per i tipi. Considera il seguente oggetto State :


local State = {
Key = "TimesClicked",
Value = 0
}

Senza generici, il tipo per questo oggetto sarebbe il seguente:


type State = {
Key: string,
Value: number
}

Tuttavia, potresti voler che il tipo per Value sia basato sul valore in arrivo, dove entrano in gioco i generici:


type GenericType<T> = T

Il <T> indica un tipo che può essere impostato a qualsiasi cosa. Il modo migliore per visualizzarlo è come 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 parentesi.


type Map<K, V> = {[K]: V}

Per rielaborare l'oggetto State da utilizzare in precedenza per utilizzare un inserisci / scrivi:


type State<T> = {
Key: string,
Value: T
}

Generici di funzione

Le funzioni possono anche utilizzare i generici. L'esempio State inferisce il valore di T dalla funzione degli argomenti in arrivo.

Per definire una funzione generica, aggiungi un <> alla funzione del nome:


local function State<T>(key: string, value: T): State<T>
return {
Key = key,
Value = value
}
end
local Activated = State("Activated", false) -- Stato<boolean>
local TimesClicked = State("TimesClicked", 0) -- State<number>

Tipo di esportazioni

Per rendere possibile l'uso di un tipo al di fuori di un ModuleScript , usa la parola chiave export :

Modulo di tipi in ReplicatedStorage

export type Cat = {
Name: string,
Meow: (Cat) -> ()
}
Script che utilizza 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()