O Luau suporta um sistema de tipo gradual através do uso de anotações de tipo e inferência de tipo.Esses tipos são usados para fornecer avisos, erros e sugestões melhores no Editor de Script.
Defina um digitar
Use a palavra-chave type para definir seus próprios tipos:
type Vector2 = {x: number, y: number}
Modos de inferência
Existem três modos de inferência do tipo Luau que podem ser definidos na primeira linha de um Script :
- --!nocheck — Não verifique tipos.
- --!nonstrict — Apenas afirma tipos de variáveis se forem explicitamente anotados.
- --!strict — Afirma todos os tipos com base no digitarinferido ou explicitamente anotado.
Os modos --!nonstrict e --!strict controlam quão rigoroso o verificador de tipos é ao inferir e verificar tipos para variáveis e funções.Qualquer tipo de correspondência incorreta em scripts é destacado no Editor de Scripts e aparece como advertências na janela Análise de Scripts.
Tipos
Uma anotação de tipo pode ser definida usando o operador : após uma variável local, seguido por uma definição de tipo.Por padrão, no modo nonstrict , todas as variáveis são atribuídas ao tipo any.
local foo: string = "bar"local x: number = 5
Existem quatro tipos primitivos que podem ser usados em uma anotação:
- nil - sem valor
- boolean - true or false
- number - um valor numérico
- string - texto
Dentro do Roblox, todas as Classes, tipos de dados e enums têm seus próprios tipos que você pode verificar contra:
local somePart: Part = Instance.new("Part")local brickColor: BrickColor = somePart.BrickColorlocal material: Enum.Material = somePart.Material
Para tornar um tipo opcional, use um ? no final da anotação:
local foo: string? = nil
Isso permitirá que a variável seja o tipo especificado (neste caso string ) ou nil.
Tipos literais
Você também pode lançar strings e booleanos para valores literais em vez de usar string e boolean :
local alwaysHelloWorld: "Hello world!" = "Hello world!"alwaysHelloWorld = "Just hello!" -- Erro de tipo: o tipo 'Apenas saudar!' não pôde ser convertido em 'Olá mundo!'local alwaysTrue: true = false -- Type error: Type 'false' could not be converted into 'true'
Tipos de lançamento
Às vezes, você pode precisar ajudar o verificador de tipos a castar explicitamente um valor para um tipo diferente com o operador :::
local myNumber = 1local myString: stringmyString = myNumber -- Não está bem; digite erro de conversãomyString = myNumber :: any -- OK; todas as expressões podem ser convertidas para 'qualquer'local myFlag = myNumber :: boolean -- Not OK; types are unrelated
Tipagem de função
Considere a seguinte função:
local function add(x, y)
return x + y
end
Essa função adiciona x a y, mas erra se uma ou ambas forem uma string / cadeia / texto.Luau não sabe que essa função só pode usar números.Para evitar essa categoria de problema, adicione tipos aos parâmetros:
local function add(x: number, y: number)
return x + y
end
Luau agora sabe que a função recebe dois números e lança um aviso se você tentar passar qualquer coisa que não seja um número para a função:
add(5, 10)add(5, "foo") -- Type error: string could not be converted into number
Para definir um digitarde retorno, coloque um operador : no final da definição da função:
local function add(x: number, y: number): number
Para retornar vários tipos, coloque os tipos em parênteses:
local function FindSource(script: BaseScript, pattern: string): (string, number)
return 42, true -- Erros de tipo
end
Defina um digitarfuncional
Um tipo funcional pode ser definido usando a síntese (in) -> out. Usando as funções dos exemplos anteriores, os tipos das funções são:
type add = (x: number, y: number) -> numbertype FindSource = (script: BaseScript, pattern: string) -> (string, number)
Tipos de tabela
O Luau não tem um digitartable ; em vez disso, os tipos de tabela são definidos usando a síntese {}.Uma maneira de definir tabelas é usando a síntese {type}, que define um digitarde lista.
local numbers: {number} = {1, 2, 3, 4, 5}local characterParts: {Instance} = LocalPlayer.Character:GetChildren()
Defina tipos de índice usando {[indexType]: valueType} :
local numberList: {[string]: number} = {Foo = 1,Baz = 10}numberList["bar"] = true -- Type error: boolean can't convert to number
As tabelas também podem ter índices de corda explícitos definidos em um digitar.
type Car = {
Speed: number,
Drive: (Car) -> ()
}
local function drive(car)
-- Sempre vá para o limite de velocidade
end
local taxi: Car = {Speed = 30, Drive = drive}
Variadics
Aqui está uma função que calcula a soma de uma quantidade arbitrária de números:
local function addLotsOfNumbers(...)
local sum = 0
for _, v in {...} do
sum += v
end
return sum
end
Como esperado, essa função pode tomar qualquer valor, e o verificador de tipos não irá emitir um aviso se você fornecer um digitarinválido, como um string.
print(addLotsOfNumbers(1, 2, 3, 4, 5)) -- 15print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- Attempt to add string to number
Em vez disso, atribua um tipo ao ..., assim como você atribui qualquer outro digitar:
local function addLotsOfNumbers(...: number)
E agora, a segunda linha levanta um erro de tipo.
print(addLotsOfNumbers(1, 2, 3, 4, 5))print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- Erro de tipo: a string não pôde ser convertida em número
No entanto, isso não funciona ao escrever uma definição de tipo funcional:
type addLotsOfNumbers = (...: number) -> number -- Expected type, got ':'
Em vez disso, use a síntese ...type para definir um digitarvariável.
type addLotsOfNumbers = (...number) -> number
Uniões e interseções
Você pode até definir um tipo como dois ou mais tipos usando uma união ou interseção:
type numberOrString = number | stringtype type1 = {foo: string}type type2 = {bar: number}type type1and2 = type1 & type2 -- {foo: string / cadeia / texto} & {bar: número}local numString1: numberOrString = true -- Erro de tipolocal numString2: type1and2 = {foo = "hello", bar = 1}
Defina um digitarinferido
Você pode usar a função typeof na definição de tipo para tipos inferidos:
type Car = typeof({Speed = 0,Wheels = 4}) --> Car: {Speed: number, Wheels: number}
Uma maneira de usar typeof é definir um tipo metável usando setmetatable dentro da função typeof:
type Vector = typeof(setmetatable({}::{x: number,y: number}, {}::{__add: (Vector, Vector|number) -> Vector}))-- Vector + Vector would return a Vector type
Genéricos
Genéricos estão em parâmetros de nível básico para tipos. Considere o seguinte ObjetoState :
local State = {Key = "TimesClicked",Value = 0}
Sem genéricos, o tipo para este objeto seria o seguinte:
type State = {Key: string,Value: number}
No entanto, você pode querer que o tipo para Value seja baseado no valor recebido, onde os genéricos entram:
type GenericType<T> = T
O <T> denota um tipo que pode ser definido para qualquer coisa. A melhor maneira de visualizar isso é como um digitarde substituição.
type List<T> = {T}local Names: List<string> = {"Bob", "Dan", "Mary"} -- O tipo se torna {string / cadeia / texto}local Fibonacci: List<number> = {1, 1, 2, 3, 5, 8, 13} -- Type becomes {number}
Genéricos também podem ter várias substituições dentro dos parênteses.
type Map<K, V> = {[K]: V}
Para reprocessar o objeto State de antes para usar um digitargenérico:
type State<T> = {Key: string,Value: T}
Gêneros de função
Funções também podem usar genéricos. O exemplo State inferiu o valor de T a partir dos argumentos de entrada da função.
Para definir uma função genérica, adicione um <> à função do nome:
local function State<T>(key: string, value: T): State<T>
return {
Key = key,
Value = value
}
end
local Activated = State("Activated", false) -- Estado<boolean>
local TimesClicked = State("TimesClicked", 0) -- State<number>
Tipos de exportação
Para torná-lo assim que um tipo possa ser usado fora de um ModuleScript , use a palavra-chave export:
Tipos de Módulo no ReplicatedStorage
export type Cat = {Name: string,Meow: (Cat) -> ()}
Script Usando o Módulo de Tipos
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()