Vérification du type

*Ce contenu est traduit en utilisant l'IA (Beta) et peut contenir des erreurs. Pour consulter cette page en anglais, clique ici.

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.BrickColor
local 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 = 1
local myString: string
myString = myNumber -- Pas OK ; erreur de conversion de type
myString = 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) -> number
type 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)) -- 15
print(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 | string
type type1 = {foo: string}
type type2 = {bar: number}
type type1and2 = type1 & type2 -- :{foo: chaîne} & {bar: number}
local numString1: numberOrString = true -- Type d'erreur
local 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()