The code provided to review is in Typed Luau with an example of how to use it.
The approach I am using has restrictions, such as that extend can only keep the types until the fourth .extend in this case and that the variadic types intended to be used as the constructor for the class don’t pass to the next class past the first pass. The point of the review is primarily to gain insight and hopefully reduce these restrictions as I am not fully satisfied with this approach.
There are many more restrictions, however they are workable. Such as the public, static, method, and private property types responding to the first value each property is set to. That each of these properties is passed to the next class via the extends method and these properties are stored within the type, until the fourth in this case, which can only use the types of the first 3 classes. And more.
Supporting Types
local a = function() end
local b = {}
type Meta = nil
type Feature = nil
type RawObject<B,C> = B & C
type Object<A,B,C,D,E...> = typeof(setmetatable({},
{} :: {
static: A,
method: B,
public: C,
private: D,
constr: (E...)->RawObject<B,C>
}
)) & RawObject<B,C>
type Creator<A,B,C,D,E...> = {
static: A, method: B, public: C, private: D,
SetConstructor: (
self: Creator<A,B,C,D,E...>,
constr: (self: Object<A,B,C,D,E...>, E...)->()
) -> ()
}
type Super<E...> = typeof((nil :: typeof(
function()
--[[Super]]--
function b:super(...: E...)
if self and a(self) then end
end
return b.super
end
))())
type ExtendCreator<A,B,C,D,E...,J...> = {
static: A, method: B, public: C, private: D,
SetConstructor: (
self: ExtendCreator<A,B,C,D,E...,J...>,
constr: (self: Object<A,B,C,D,E...> & {
super: Super<E...>
}, J...)->()
) -> ()
}
In the code provided I have made it so the variadic types don’t cause an issue with the autocomplete but I have commented what I wish for the autocomplete to act like in the below code and in the example.
type Class3<A,B,C,D,E...> = A & {
create: (E...) -> RawObject<B,C>,
extend: <F,G,H,I,J...>(name: string, func: (
creator: ExtendCreator<F & A,G & B,H & C,I & D,E...,J...>,
meta: Meta,
feature: Feature
-- Should be J... v
)->())->Class3<A,B,C,D,E...>
}
type Class2<A,B,C,D,E...> = A & {
create: (E...) -> RawObject<B,C>,
extend: <F,G,H,I,J...>(name: string, func: (
creator: ExtendCreator<F & A,G & B,H & C,I & D,E...,J...>,
meta: Meta,
feature: Feature
-- Should be J... v
)->())->Class3<F & A,G & B,H & C,I & D,E...>
}
type Class1<A,B,C,D,E...> = A & {
create: (E...) -> RawObject<B,C>,
extend: <F,G,H,I,J...>(name: string, func: (
creator: ExtendCreator<F & A,G & B,H & C,I & D,E...,J...>,
meta: Meta,
feature: Feature
-- Should be J... v
)->())->Class2<F & A,G & B,H & C,I & D,E...>
}
type New = <A,B,C,D,E...>(name: string, func: (
creator: Creator<A,B,C,D,E...>,
meta: Meta,
feature: Feature
)->()) -> Class1<A,B,C,D,E...>
Example
local a = nil :: New
a("",function(creator, meta, feature)
creator.public = {a = 1}
creator.private = {b = 1}
creator.method = {c = 1}
creator.static = {d = 1}
creator:SetConstructor(function(self, h: string, i: number)
-- For verifying that metatable autocomplete still functions properly
--getmetatable(self)
end)
end).extend("", function(creator, meta, feature: Feature)
creator.public = {e = 1}
creator.private = {f = 1}
creator.method = {g = 1}
creator.static = {h = 1}
creator:SetConstructor(function(self, j: Instance, k: string)
self:super() -- Is: super(string, number)
end)
end).extend("", function(creator, meta: nil, feature: nil)
creator.public = {i = 1}
creator.private = {j = 1}
creator.method = {k = 1}
creator.static = {l = 1}
creator:SetConstructor(function(self, a1: string, a2: number)
self:super() -- Want it to be: super(Instance, string)
end)
end) -- Want .extend().extend()... to work similarly to those above, constantly expanding the types
-- Instead it stagnates
My first post, but hopefully it is in the right category, tried to justify it. Thanks!