I not understand, but else i understand and it helped me out to understand: Thanks!
When typeof
appears in type position, it means something a little bit different than the typeof()
function that you see in regular Lua.
“Type position” means a position in your code where the parser is expecting to see a type and not a value. Type annotations and after the =
in a type
definition, in other words.
In type position, typeof
is a way to say “whatever type this expression produces.” Some examples:
--!strict
local a = 55 -- Luau infers that a: number
local b: typeof(a) = 22 -- b has whatever type a has. Number, in this case.
local c = Player.CFrame -- c has type CFrame
local v = Vector3.new(0, 0, 0) -- v has type Vector3
local d: typeof(c * v) = c -- d has whatever type c * v would have, if you
-- were to run it. c * v is not actually
-- executed!
Okay I see, thank you. Though I have a few more questions.
Why does local x: typeof({ }) = { }
work, but local x: table = { }
doesn’t? Why aren’t tables supported? Will more datatypes like function
, thread
and userdata
(excluding roblox ones like Instance
, Vector3
, etc) be supported in the future?
Quoted from zuexcg.
Is there any way to express inheritance at the moment? The most obvious use for something like this is having a piece of code that accepts all BaseParts, not just ones that have been explicitly whitelisted in a union (that and Part|WedgePart|CornerWedgePart|MeshPart|Union
and so forth is really not intuitive or fun to write).
Being able to instead write something like inherits<BasePart>
(but with better syntax obviously) would be nice.
Additionally, I don’t think I ever got an answer on including an Array type by default. It’s not a very big deal but arrays are very common so it should probably be built in.
I not am good with Roblox inheritance, but hope it help you:
What about inheritance?
A quick explanation of inheritance to those new to OOP.
What about inheritance?
A quick explanation of inheritance to those new to OOP.
From here: All about Object Oriented Programming
@Dekkonot, a idea would be:
local MyPart = {}
function MyPart.new()
local NewMyPart = {} --Your new Part
return setmetatable(NewClass, BasePart) --If i am following the tutorial i linked you, so you can inherit from BasePart class. But i am unsure if Roblox will leave you do this…
end
return MyPart
And if you want to make that the default Instance.new()
function can use your default class, so just read this: Is it possible to make own Instances? - #11 by sjr04
Is here any method to make that a function return nil, also was a void type function?
While I appreciate the lesson, I’m actually referring to the Roblox class inheritance that already exists. There isn’t any documentation for this on the developer hub but the various classes all inherit from other classes on Roblox.
For example, Part inherits from a class called BasePart. You can use Instance:IsA in code to check inheritance like this, which is helpful since abstract classes like BasePart cover a lot of ground. Like I said above, it includes all of the part classes, meshparts, and unions.
I’m specifically asking for a way to specify this inheritance. There’s an obvious benefit to allowing all Parts (whether they be wedges, blocks, or meshes) to be specified as a type easily.
Is there any way to express inheritance at the moment? The most obvious use for something like this is having a piece of code that accepts all BaseParts, not just ones that have been explicitly whitelisted in a union (that and
Part|WedgePart|CornerWedgePart|MeshPart|Union
and so forth is really not intuitive or fun to write).Being able to instead write something like
inherits<BasePart>
(but with better syntax obviously) would be nice.
Why not just use BasePart?
local t:BasePart = Instance.new"Part"
-- or with generics
type inherits<T> = T
local t2:inherits<BasePart> = Instance.new"Part"
It doesn’t check when IsA is used, so this gives a warning.
local t:BasePart = Instance.new"Part"
if t:IsA"Part" then
print(t.Shape)
end
Why does
local x: typeof({ }) = { }
work, butlocal x: table = { }
doesn’t? Why aren’t tables supported? Will more datatypes likefunction
,thread
anduserdata
(excluding roblox ones likeInstance
,Vector3
, etc) be supported in the future?
Tables and functions aren’t represented with function
and table
, instead they have their own syntax
type f = () => ()
-- takes no arguments, returns no values
type f2 = (string) => boolean
-- takes a string argument, returns a boolean
type f3 = (string,number?) => (number,number?)
-- takes a string and optional number, returns a number and an optional number
type t = {[number]:string}
-- keys are numbers, values are strings
type t2<T> = {[number]:T}
-- keys are numbers, values are the specified generic type
type t3 = {a:number,b:string,c:t3?}
-- key 'a' is a number, key 'b' is a string, key 'c' is a t3 or nil
Hopefully we get thread and userdata, although userdata would only be for userdata created with newproxy.
I suppose I could just use BasePart. I’ll admit I forgot that the type system was just checking for various members.
Nevermind, then – the point about an array type still stands though.
Bug…?
I suppose that would work but that won’t prevent non-sequential keys from being used, or non-integer keys
It seems like compound if statements have some issues:
local part0: BasePart? = workspace:FindFirstChild("Part0")
local part1: BasePart? = workspace:FindFirstChild("Part1")
if part0 and part1 then
-- This gives the following warning in Script Analysis:
-- Non-table type BasePart | nil does not have key "Name"
print(part0.Name)
print(part1.Name)
end
if part0 then
if part1 then
-- This gives no warnings
print(part0.Name)
print(part1.Name)
end
end
Also, explicit nil checking like this gives the same warning as the above:
if part0 ~= nil then
print(part0.Name)
end
Side note, it would be really cool if type annotating as BasePart / Model / some other type of instance would pass onto FindFirstChild and have it only return that type. Or maybe there needs to be stricter checks for FindFirstChild/similar methods and types. Right now declaring something as BasePart like I did above but having FindFirstChild still able to return any type of Instance (or none) without warning me seems bad.
Using SetAsync on a DataStore and passing a table with a string and two tables (that have three numbers in them) seems to not work. Worked in nonstrict mode, but not strict.
type
is a keyword for defining custom types that aren’t part of Luau normally. Think of it as aliasing a word to a type. It’s not a function. The {x: number, y: number}
is defining what the type is. Later on, you can use the custom type like any other type:
function point_thing(point: Point) => boolean
return point.x == point.y
end
Just makes it easier than putting {x: number, y: number}
every time.
And I have realized that you posted in January. Oops.
Not sure if this was mentioned already, but functions such as FindFirstChild
get warnings on them even when their ‘third’ argument (recursive?) is optional.
The tooltip also doesn’t show me the return type of my function or the argument types. It also says “3 arguments required” when one is optional.
Another thing was that it was giving me a warning for trying to use this function even though the expected return type is completely viable
Also, even though I make sure the object is of type Instance, it does not autocomplete the expected functions from an Instance type.
FindFirstChild doesn’t even take 3 arguments, only 2 (the second one being optional as you said).
Also, why does Luau annotations have to be the only way to mark types? Isn’t comment based deduction better and cleaner?
I honestly find these much easier to read.
This is JSDocs for JavaScript / Node.js that is used in IDEs like Visual Studio and it prevents code bloat by using comments, while also being able to provide detailed and precise descriptions of variables, parameters, functions, and etc as you type them out which is very very useful and not currently possible when all you can do is annotate a type.
FindFirstChild Takes 3 arguments.
When you call a findfirstchild(), you use a syntax suger “:”. When this is used, lua automatically takes the object “:” was used as a first argument, which can be referred by using the “self” global.
local obj = {}
obj.__index = obj
function obj.new(name: string) => object
local newObj = setmetatable({}, obj)
newObj.Name = name
return newObj
end
function obj:printName()
print(self.Name) --self refers to newObject created in script after this module script
end
type object = typeof(obj.new)
return obj
--Script
local objModule = require(obj)
local newObject = objModule.new("Bob")
newObject:printName() --By using ":", we tell the function that self refers to newObject
>>Bob
In same manner, the FindFirstChild(name, recursive)
takes 3 arguments because it uses “:” to the object you are searching in
tl;dr
Object:Method(…) == Object.Method(Object, …)
no matter how the function’s made