Luau prend en charge un système de type graduel en utilisant des annotations de type et des inférences de type. Ces types sont utilisés pour fournir de meilleures avertissements, d'erreurs et de suggestions dans le Éditeur de script.
Définir un type
Utilisez le mot-clé type pour définir vos propres types :
type Vector2 = {x: number, y: number}
Modes d'inférence
Il y a trois modes d'inférence de type Luau qui peuvent être définis sur la première ligne d'un Script :
- --!nocheck - Ne vérifiez pas les types
- --!nonstrict - Mode par défaut pour tous les scripts, ne prétend que les types variables s'ils sont explicitement annotés
- --!strict - Définit tous les types en fonction de leur taperimplicite ou explicitement annoté
Le mode par défaut pour le type checker est --!nonstrict . Les deux autres modes contrôlent la façon dont le type checker est avec inferring et vérifier les types pour les variables et les fonctions. Tous les types de mises en évidence dans les scripts sont indiqués dans le Éditeur de script et sur la surface comme des avertissements dans la fenêtre d'analyse du script.
Types
Une type annotation peut être définie en utilisant l'opérateur : après une variable locale, suivi d'une définition de type. Par défaut, dans le mode nonstrict , toutes les variables sont attribuées le type any.
local foo: string = "bar"local x: number = 5
Il y a quatre types primitifs qui peuvent être utilisés dans une annotation :
- nil - pas de valeur
- boolean - true ou false
- number - une valeur numérique
- string - texte
Dans Roblox, toutes les Classes, types de données et enums ont leur propre type que vous pouvez vérifier contre :
local somePart: Part = Instance.new("Part")local brickColor: BrickColor = somePart.BrickColorlocal material: Enum.Material = somePart.Material
Pour rendre un type optionnel, utilisez un ? à la fin de l'annotation :
local foo: string? = nil
Ceci permettra à la variable d'être soit le type spécifié (dans ce cas string ) ou nil .
Type de données Littéraire
Vous pouvez également lancer des chaînes et des booleans à des valeurs littéraires au lieu d'utiliser string et boolean :
local alwaysHelloWorld: "Hello world!" = "Hello world!"alwaysHelloWorld = "Just hello!" -- Type error: Le type « Just hello ! » ne pouvait pas être converti en « Hello monde! »local alwaysTrue: true = false -- Type error: Type 'false' could not be converted into 'true'
Type Casts
Parfois, vous devrez peut-être aider le typechecker en lançant explicitement une valeur dans un autre type avec l'opérateur :: :
local myNumber = 1local myString: stringmyString = myNumber -- Pas OK ; erreur de conversion de typemyString = myNumber :: any -- OK; toutes les expressions peuvent être exécutées à « n'importe lequel »local myFlag = myNumber :: boolean -- Not OK; types are unrelated
Type de fonction
Considerons la fonction suivante :
local function add(x, y)
return x + y
end
Cette fonction ajoute x à y, mais les erreurs si l'un ou les deux d'entre eux est une chaîne. Luau ne sait pas que cette fonction ne peut utiliser que des chiffres. Pour éviter cette catégorie de problème, ajoutez des types aux paramètres :
local function add(x: number, y: number)
return x + y
end
Luau sait maintenant que la fonction prend deux nombres et lance une avertissement si vous essayez de passer n'importe quoi qui n'est pas un nombre dans la fonction :
add(5, 10)add(5, "foo") -- Type error: string could not be converted into number
Pour définir un taperde retour, mettez un : opérateur à la fin de la définition de la fonction :
local function add(x: number, y: number): number
Pour renvoyer plusieurs types, placez les types dans les parenthèses :
local function FindSource(script: BaseScript, pattern: string): (string, number)
return 42, true -- Type d'erreurs
end
Définir un type fonctionnel
Un type fonctionnel peut être défini en utilisant la syntaxe (in) -> out. En utilisant les fonctions des exemples précédents, les types des fonctions sont :
type add = (x: number, y: number) -> numbertype FindSource = (script: BaseScript, pattern: string) -> (string, number)
Types de tableaux
Luau n'a pas de tapertable mais plutôt, les types de table sont définis en utilisant la syntaxe {}. L'une des façons d'utiliser les tables est d'utiliser la syntaxe {type}, qui définit un taperde liste.
local numbers: {number} = {1, 2, 3, 4, 5}local characterParts: {Instance} = LocalPlayer.Character:GetChildren()
Définissez les types d'index en utilisant {[indexType]: valueType} :
local numberList: {[string]: number} = {Foo = 1,Baz = 10}numberList["bar"] = true -- Type error: boolean can't convert to number
Les tables peuvent également avoir des index de chaîne explicitement définis dans un taper.
type Car = {
Speed: number,
Drive: (Car) -> ()
}
local function drive(car)
-- Toujours allez à la limite de vitesse
end
local taxi: Car = {Speed = 30, Drive = drive}
Variadics
Voici une fonction qui calcule la somme d'un nombre arbitraire de nombres :
local function addLotsOfNumbers(...)
local sum = 0
for _, v in {...} do
sum += v
end
return sum
end
Comme prévu, cette fonction peut prendre n'importe quelle valeur, et le typechecker ne lèvera pas d'avertissement si vous fournissez un taperinvalide, comme un string .
print(addLotsOfNumbers(1, 2, 3, 4, 5)) -- 15print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- Attempt to add string to number
Au lieu de cela, attribuez un type à ..., comme vous le faites pour n'importe quel autre taper:
local function addLotsOfNumbers(...: number)
Et maintenant, la deuxième ligne soulève une erreur de type.
print(addLotsOfNumbers(1, 2, 3, 4, 5))print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- Type d'erreur : le string n'a pas pu être converti en numéro
Cependant, cela ne fonctionne pas lors de l'écriture d'une définition de type fonctionnel :
type addLotsOfNumbers = (...: number) -> number -- Expected type, got ':'
Au lieu de cela, utilisez la syntaxe ...type pour définir un tapervarias.
type addLotsOfNumbers = (...number) -> number
Unités et intersections
Vous pouvez même définir un type comme deux types ou plus en utilisant une union ou une intersection :
type numberOrString = number | stringtype type1 = {foo: string}type type2 = {bar: number}type type1and2 = type1 & type2 -- :{foo: chaîne} & {bar: number}local numString1: numberOrString = true -- Type d'erreurlocal numString2: type1and2 = {foo = "hello", bar = 1}
Définir un type implicite
Vous pouvez utiliser la fonction typeof dans une définition de type pour les types implicites :
type Car = typeof({Speed = 0,Wheels = 4}) --> Car: {Speed: number, Wheels: number}
L'une des façons d'utiliser typeof est d'utiliser un type de tableau métatique en utilisant setmetatable à l'intérieur de la fonction typeof :
type Vector = typeof(setmetatable({}::{x: number,y: number}, {}::{__add: (Vector, Vector|number) -> Vector}))-- Vector + Vector would return a Vector type
Génériques
Les génériques sont des paramètres de niveau de base pour les types. Considérez l'objet suivant State :
local State = {Key = "TimesClicked",Value = 0}
Sans génériques, le type pour cet objet serait comme suivant :
type State = {Key: string,Value: number}
Cependant, vous voudrez peut-être que le type pour Value soit basé sur la valeur entrante, ce qui est l'endroit où les génériques viennent :
type GenericType<T> = T
Le <T> représente un type qui peut être défini sur n'importe quoi. La meilleure façon de visualiser ceci est comme un taperde substitution.
type List<T> = {T}local Names: List<string> = {"Bob", "Dan", "Mary"} -- Le type devient {chaîne}local Fibonacci: List<number> = {1, 1, 2, 3, 5, 8, 13} -- Type becomes {number}
Les génériques peuvent également avoir plusieurs substitutions à l'intérieur des parenthèses.
type Map<K, V> = {[K]: V}
Pour réutiliser l'objet State de plus tôt pour utiliser un tapergénérique :
type State<T> = {Key: string,Value: T}
Génériques de fonction
Les fonctions peuvent également utiliser des génériques. L'exemple State infère la valeur de T à partir des arguments entrants de la fonction.
Pour définir une fonction générique, ajoutez un <> à la nom de la fonction :
local function State<T>(key: string, value: T): State<T>
return {
Key = key,
Value = value
}
end
local Activated = State("Activated", false) -- État <button>
local TimesClicked = State("TimesClicked", 0) -- State<number>
Type Exports
Pour que quelqu'un puisse l'utiliser en dehors d'un ModuleScript, utilisez le mot-clé export :
Tapez le module dans ReplicatedStorage
export type Cat = {Name: string,Meow: (Cat) -> ()}
Script à l'aide du module Type
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()