يدعم Luau نظام نوع تدريجي من خلال استخدام تعليقات النوع واستدلال النوع. تُستخدم هذه الأنواع لتقديم تحذيرات وأخطاء واقتراحات أفضل في محرر السكريبت.
تعريف نوع
استخدم الكلمة الرئيسية type لتعريف أنواعك الخاصة:
type Vector2 = {x: number, y: number}
أوضاع الاستدلال
هناك ثلاثة أوضاع استدلال نوع في Luau يمكن تعيينها في السطر الأول من Script:
- --!nocheck — لا تحقق من الأنواع.
- --!nonstrict — تؤكد فقط على أنواع المتغيرات إذا كانت مُعَلَّمة صراحة.
- --!strict — تتحقق من جميع الأنواع بناءً على النوع المستدل عليه أو المُعَلَّم صراحة.
تتحكم أوضاع --!nonstrict و --!strict في مدى صرامة فاحص النوع في استدلال والتحقق من أنواع المتغيرات والدوال. يتم تمييز أي عدم تطابق في الأنواع في السكريبتات في محرر السكريبت وظهوره كتحذيرات في نافذة تحليل السكريبت.
لتعيين وضع افتراضي لجميع السكريبتات يمكنك تجاوزها حسب الحاجة، انظر Workspace.LuauTypeCheckMode.
الأنواع
يمكن تعريف تعليق نوع باستخدام العامل : بعد متغير محلي، متبوعًا بتعريف نوع. بشكل افتراضي، في وضع nonstrict، يتم تعيين جميع المتغيرات إلى النوع any.
local foo: string = "bar"local x: number = 5
هناك أربعة أنواع بدائية يمكن استخدامها في تعليق:
- nil - لا قيمة
- boolean - true أو false
- number - قيمة عددية
- string - نص
داخل Roblox، تحتوي جميع الفئات، وأنواع البيانات، والتعدادات على أنواعها الخاصة التي يمكنك التحقق منها:
local somePart: Part = Instance.new("Part")local brickColor: BrickColor = somePart.BrickColorlocal material: Enum.Material = somePart.Material
لجعل نوع ما اختياريًا، استخدم ? في نهاية التعليق:
local foo: string? = nil
سيسمح ذلك للمتغير بأن يكون إما من النوع المحدد (في هذه الحالة string) أو nil.
الأنواع الحرفية
يمكنك أيضًا تحويل السلاسل النصية وboolean إلى قيماً حرفية بدلاً من استخدام string و boolean:
local alwaysHelloWorld: "Hello world!" = "Hello world!"alwaysHelloWorld = "Just hello!" -- خطأ في النوع: لا يمكن تحويل النوع '"Just hello!"' إلى '"Hello world!"'local alwaysTrue: true = false -- خطأ في النوع: لا يمكن تحويل 'false' إلى 'true'
تحويلات النوع
في بعض الأحيان، قد تحتاج إلى مساعدة فاحص النوع من خلال تحويل قيمة إلى نوع آخر صراحةً باستخدام العامل :::
local myNumber = 1local myString: stringmyString = myNumber -- غير مقبول؛ خطأ في تحويل النوعmyString = myNumber :: any -- مقبول؛ يمكن تحويل جميع التعابير إلى 'any'local myFlag = myNumber :: boolean -- غير مقبول؛ الأنواع غير مرتبطة
نوع الدوال
اعتبر الدالة التالية:
local function add(x, y)
return x + y
end
هذه الدالة تضيف x إلى y، لكنها تخطئ إذا كان أحدهما أو كليهما سلسلة نصية. لا يعرف Luau أن هذه الدالة يمكنها استخدام الأرقام فقط. لمنع هذه الفئة من المشاكل، أضف أنواعًا إلى المعاملات:
local function add(x: number, y: number)
return x + y
end
يعرف Luau الآن أن الدالة تأخذ رقمين ويلقي تحذيرًا إذا حاولت تمرير أي شيء ليس رقمًا إلى الدالة:
add(5, 10)add(5, "foo") -- خطأ في النوع: لا يمكن تحويل السلسلة إلى رقم
لتعريف نوع الإرجاع، ضع عامل : في نهاية تعريف الدالة:
local function add(x: number, y: number): number
لإرجاع أنواع متعددة، ضع الأنواع بين قوسين:
local function FindSource(script: BaseScript, pattern: string): (string, number)
return 42, true -- أخطاء في النوع
end
تعريف نوع وظيفي
يمكن تعريف نوع وظيفي باستخدام الصيغة (in) -> out. باستخدام الوظائف من الأمثلة السابقة، تكون أنواع الوظائف كما يلي:
type add = (x: number, y: number) -> numbertype FindSource = (script: BaseScript, pattern: string) -> (string, number)
أنواع الجداول
ليس لدى Luau نوع table؛ بدلاً من ذلك، يتم تعريف أنواع الجداول باستخدام صيغة {}. إحدى طرق تعريف الجداول هي استخدام صيغة {type}، والتي تحدد نوع القائمة.
local numbers: {number} = {1, 2, 3, 4, 5}local characterParts: {Instance} = LocalPlayer.Character:GetChildren()
حدد أنواع الفهارس باستخدام {[indexType]: valueType}:
local numberList: {[string]: number} = {Foo = 1,Baz = 10}numberList["bar"] = true -- خطأ في النوع: لا يمكن تحويل boolean إلى رقم
يمكن أن تحتوي الجداول أيضًا على فهارس نصية صريحة محددة في نوع.
type Car = {
Speed: number,
Drive: (Car) -> ()
}
local function drive(car)
-- الالتزام دائمًا بحد السرعة
end
local taxi: Car = {Speed = 30, Drive = drive}
المتغيرات المتعددة
إليك دالة تحسب مجموع عدد غير محدد من الأرقام:
local function addLotsOfNumbers(...)
local sum = 0
for _, v in {...} do
sum += v
end
return sum
end
كما هو متوقع، يمكن أن تأخذ هذه الدالة أي قيمة، ولن يرفع فاحص النوع تحذيرًا إذا قدمت نوعًا غير صالح، مثل string.
print(addLotsOfNumbers(1, 2, 3, 4, 5)) -- 15print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- محاولة لإضافة سلسلة إلى رقم
بدلاً من ذلك، عيّن نوعًا إلى الـ ...، تمامًا كما تعين أي نوع آخر:
local function addLotsOfNumbers(...: number)
والآن، يرفع السطر الثاني خطأ في النوع.
print(addLotsOfNumbers(1, 2, 3, 4, 5))print(addLotsOfNumbers(1, 2, "car", 4, 5)) -- خطأ في النوع: لا يمكن تحويل السلسلة إلى رقم
ومع ذلك، لا تعمل هذه عند كتابة تعريف نوع وظيفي:
type addLotsOfNumbers = (...: number) -> number -- النوع المتوقع، حصلت على ':'
بدلاً من ذلك، استخدم الصيغة ...type لتعريف نوع متغيرات متعددة.
type addLotsOfNumbers = (...number) -> number
الإتحادات والتقاطعات
يمكنك حتى تعريف نوع مزدوج أو أكثر باستخدام اتحاد أو تقاطع:
type numberOrString = number | stringtype type1 = {foo: string}type type2 = {bar: number}type type1and2 = type1 & type2 -- {foo: string} & {bar: number}local numString1: numberOrString = true -- خطأ في النوعlocal numString2: type1and2 = {foo = "hello", bar = 1}
تعريف نوع مستدل
يمكنك استخدام دالة typeof في تعريف النوع للأنواع المستدل عليها:
type Car = typeof({Speed = 0,Wheels = 4}) --> Car: {Speed: number, Wheels: number}
إحدى الطرق لاستخدام typeof هي لتحديد نوع الـ metatable باستخدام setmetatable داخل دالة typeof:
type Vector = typeof(setmetatable({}::{x: number,y: number}, {}::{__add: (Vector, Vector|number) -> Vector}))-- Vector + Vector سيعيد نوع Vector
الجنريك
الجنريك هي على مستوى أساسي بارامترات للأنواع. اعتبر الكائن State التالي:
local State = {Key = "TimesClicked",Value = 0}
بدون الجنريك، سيكون نوع هذا الكائن كما يلي:
type State = {Key: string,Value: number}
ومع ذلك، قد ترغب في أن يكون النوع لـ Value يعتمد على القيمة الواردة، وهنا تأتي الجنريك:
type GenericType<T> = T
يشير <T> إلى نوع يمكن تعيينه لأي شيء. أفضل طريقة لتصوير ذلك هي كنوع بديل.
type List<T> = {T}local Names: List<string> = {"Bob", "Dan", "Mary"} -- يصبح النوع {string}local Fibonacci: List<number> = {1, 1, 2, 3, 5, 8, 13} -- يصبح النوع {number}
يمكن أن تحتوي الجنريك أيضًا على بدائل متعددة داخل الأقواس.
type Map<K, V> = {[K]: V}
لإعادة صياغة كائن State من السابق لاستخدام نوع جنريك:
type State<T> = {Key: string,Value: T}
الجنريك في الوظائف
يمكن أيضًا أن تستخدم الوظائف الجنريك. المثال State يستدل على قيمة T من المعاملات الواردة للدالة.
لتعريف دالة جنريك، أضف <> إلى اسم الدالة:
local function State<T>(key: string, value: T): State<T>
return {
Key = key,
Value = value
}
end
local Activated = State("Activated", false) -- State<boolean>
local TimesClicked = State("TimesClicked", 0) -- State<number>
تصدير الأنواع
لجعل نوعًا يمكن استخدامه خارج ModuleScript، استخدم الكلمة الرئيسية export:
وحدات الأنواع في ReplicatedStorageexport type Cat = {Name: string,Meow: (Cat) -> ()}
سكريبت يستخدم وحدة الأنواع
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Types = require(ReplicatedStorage.Types)
local newCat: Types.Cat = {
Name = "metatablecat",
Meow = function(self)
print(`{self.Name} قال مياو`)
end
}
newCat:Meow()