I’ve been switching most of my code to take an array as a parameter instead of varargs for this reason. It seems like something entirely doable with the syntax though, something like function takesInVarArgs(...: ...unknown)
In general, I think you should avoid varargs when you can use an array, just because it’s much easier to manage and document, and because usually you have to restructure/destructure between varargs and arrays internally, which adds to unnecessary computation.
If course, for something like Resume and FastSpawn you can’t really avoid it, since sometimes parameters can be “nil” but still present in the vararg (if you ever have code that’s using select('#', ...))
The problem there is that the user can retain a reference to the table and start fiddling around with it while it still may be in use. They can also pass a table with a metatable that does who knows what when indexed. I prefer to have “clean” APIs when possible.
Regardless, the current type system still doesn’t have an accurate way to describe actual, sequential arrays, so I’m left disappointed either way.
I’m encountering an issue with string.byte; its return type is set to be number|nil, which is accurate, but it means that anything that interacts with string.byte has to also be number|nil.
This can be fixed rather easily by type guarding against it being nil, but that’s cumbersome in some cases. I have some code that looks similiar to this, and despite me knowing that it will never be nil, I have to typecheck against string.byte’s return rather than just casting it directly to a number. We need an equivalent to as sooner rather than later.
--!strict
local function foo(bar: string): {[number]: number}
local baz: {[number]: number}
for i = 1, #bar do
baz[i] = string.byte(bar, i, i)
end
return baz
end
I’m trying to figure out how to use this, but it’s not working for me. Script Analysis repeatedly tells me to restart studio, and I have several times. Still, nothing is fixing. Any ideas on why I can’t get it to work?
This means that there is a snippet somewhere causing an internal compiler error. If you could shoot me the RBXL file, I can track it down and find the minimal repro to file a ticket.
I apologize if this problem’s been brought up here already, but I haven’t seen it yet.
An array with different types for values doesn’t seem to be working properly:
type mixedArray = {[number]: any}
local mixedTable: mixedArray = {true, 10}
W000: Type mismatch number and boolean
Strangely enough it will let me have different value types if my keys aren’t all numbers:
type mixedArray = {[number | string]: any}
local mixedTable: mixedArray = {[1] = true, ["String"] = 10}
I would love to be able to put the type’s under return’s in modules.
Since types get messy i ussaly just shove them at the bottom of the script but because of the return in modulescripts i cannot put it at the very bottom in modulescripts. Very minor thing but something I would love to be changed.
I would also love for some file which all scripts get their types from, This would be very useful for scripts which use alot of modules.
Weird question, but what’s the point of this? I see it removes the need for redundant assert() calls, but is there something special about type checking that I’m missing?
Assert and Type Cheking are totally different, assert gives you errors when executing the code, Type Cheking is while you write the code, for example, if you call a function with an assert with incorrect arguments, when executing it then it will give you an error, but with Type Checking it will give you an error when writing the arguments. And that’s just a comparison, Type Checking does much more than that.
Here’s an example of a simple function written in plain Lua (it doesn’t make much sense, but it shows how to confuse a compiler):
local function Log(boolA,vecB,vecC)
if boolA then
print(vecB.X,vecB.Y,vecB.Z)
else
print(vecC.X==true and vecC.Y or vecC.Z)
end
end
Lua doesn’t know what boolA, vecB or vecC are. boolA can be any type and has to check whether it’s a true boolean or a non-nil. It only knows that X, Y and Z are values in vecB and vecC, but it has no idea that they are numbers. No optimizations would be possible after the else statement as it doesn’t know that X, Y and Z are numbers, so it still has to check if they are something else. This bad code cannot be optimized much by a JIT compiler without the rest of the code exposed.
Here’s the same example but with types:
local function Log(boolA:boolean,vecB:Vector3,vecC:Vector3)
if boolA then
print(vecB.X,vecB.Y,vecB.Z)
else
print(vecC.X==true and vecC.Y or vecC.Z)
end
end
The compiler immediately knows that boolA is always a boolean, so it doesn’t have to check if it’s non-nil. vecC is a Vector3, so X, Y and Z are numbers, rendering the second print statement easily simplifiable to print(vecC.Z).
Furthermore, type checking can help you catch bugs in your codebase you probably would never have found without it. Many popular languages implement strict type checking.
Also, it helps the programmer understand the code better. You can look at the code, and you would understand that a certain variable is a certain type.
Hi, I have a couple questions. I’m trying to figure out what I’m doing wrong. The documentation does not seem to be pointing me in any helpful direction.
#1 - Why does this not understand that OnServerInvoke is valid?