Yo, I’m trying to write the type for a function wrapper wrap. wrap takes a function callback and should return a function with the exact same type signature as callback.
This works for most cases:
local function wrap<T..., U...>(
callback: (T...) -> (U...)
): (T...) -> (U...)
return function(...: T...): (U...)
-- do some other stuff
return callback(...)
end
end
Here, wrapped is inferred as ({ string }) -> (), and if you call wrapped with a { number } argument first and then call it again with a { string } argument, it would be inferred as ({ number} ) -> () instead for some reason. Ideally, wrap would somehow “preserve” the generics in callback.
I’ve also tried resorting to explicitly typing the wrapped callbacks, but that only half-works…
I’m not sure if type packs (T... and U...) not handling generics like I want them to is a bug. I mostly just want to know how I can write the type for wrap such that it returns a callback with the exact same type as the callback passed to it, with or without generics, if it is even possible in Luau right now.
Luau doesn’t lint anything in the below code snippet, and everything is typed correctly:
local function doGenericThing<T>(arg: {T})
print(table.concat(arg, ", "))
end
doGenericThing({ 1, 2, 3 })
doGenericThing({ 'a', 'b', 'c' })
local function typePackYay<T...>(...: T...)
print(...)
end
typePackYay(1, 'a', true)
typePackYay({ 1 }, function() end)
I’m asking if there is a way to write a type for a wrapper function so that the returned function has the same type as the passed in function. This way, whoever uses the wrapper can make more use of the Luau type checker in their code. The Luau type checker catches potential errors during the authoring of your code (not after like printing/asserting and argument would) and highlights it. This is nice because there’s less of a chance for players to encounter bugs after you’ve pushed out an update.
The solution I will have to use is to simply not type wrap and explicitly type any wrapped functions.
local function wrap(callback: any): any
return function(...)
print("hi")
return callback(...)
end
end
local function doGenericThingy<T>(arg: { T })
return table.concat(arg, ", ")
end
local wrappedGenericThingy: typeof(doGenericThingy)
wrappedGenericThingy = wrap(doGenericThingy)