Has anyone found a way to do something similar to this? type A<T...> = () -> (T...?)
I want a function that can either return T... or nil
it doesn’t work and I’ve also tried many ways it still doesn’t work for examples type A<T...> = () -> T...? type A<T...> = () -> T... | nil type A<T...> = () -> T... & nil type A<T...> = () -> (T... | nil) type A<T...> = () -> (T... & nil) type A<T...> = () -> ((T...)?) type A<T...> = () -> ((T...) | nil) type A<T...> = () -> ((T...) & nil) type A<T...> = () -> (T...) | () -> () type A<T...> = () -> () & () -> (T...)
Now, the below line doesn’t produce errors or warnings but it’s still not working as intended after I checked the typing properly: type A<T...> = () -> (T...) & () -> ()
This one always return T... never nil
You cannot make a union with a generic type-pack. The reasoning behind this is quite simple: a type-pack can have an arbitrary number of types (even zero), but a union must always be of a single type.
Considering the following case. What would A and B even be here?
type T<Pack...> = Pack... | nil
type A = T<string, boolean>
type B = T<>
I declared <T…> type pack so that it type checks methods like connect and wait
This is signal is a bit special because if the signal is dead or destroyed, it will disconnect every connections and wait threads are resumed with nil
So Wait can return as either T… or nil
For example
local s: Signal<string, number> = Signal.new()
local a, b = s:Wait()
I want the a and b variable type to be string? and number? not string and number
I know that I can just declare them manually like this a: string?, b: number?
But I want the type to automatically know that from my signal type not by manually declaring, becuase if I don’t annotate the type manually it sees a and b as string and number
I’ve tried Wait: (self: Signal<T...>) -> (T...)?
But it thinks Wait is either a function or null rather than its return type
Is there a way to annotate function like this? or is it still not implemented
Yeah, this seems like an interesting edge-case. I think what’s really happening here is that the solver (both old and new) will always infer for the first signature in the overload because both have the same parameters.
A symptom of this behavior is that flipping the order of the signatures literally changes the result.
local NumberFirst = (nil :: any) :: (() -> number) & (() -> string)
local StringFirst = (nil :: any) :: (() -> string) & (() -> number)
-- A: number, B: string
local A, B = NumberFirst(), StringFirst()
In both cases, what you’d really want would be both returning number | string, but the types don’t normalize to that for some reason. This might just be a necessary evil due to semantic subtyping.
Regardless, if this could even be ‘fixed’, you’d still run into the problem of trying to union a type-pack. This isn’t orthogonal to your use case–even the built-in type definitions run into this restriction–so a resolution should hopefully show up some day.