Hacky way of avoiding cyclic dependency to compose OOP objects inside each other and get the types? Is it possible to fix?

I looked and saw this hacky way of getting over cyclic dependency to get types into modules and was wondering if anyone can help me to get it working for OOP compositions???

The way to do it:
Example (signal.lua):

local package = script.Parent.Parent
local packages = package.Parent

type SignalModule = typeof(require(packages.signal))

local getModule = require(package.utilities.getModule)
local signalModule = getModule("signal")

-- i hate this
export type Connection = typeof((function()
	local module = require(packages.signal)
	return {} :: module.Connection
end)())

export type Signal<T...> = typeof((function()
	local module = require(packages.signal)
	return {} :: module.Signal<T...>
end)())

return require(signalModule) :: SignalModule

Car.lua

local Engine = require(script.Engine)

local Car = {}
Car.__index = Car

type self = {
	["_Engine"]: Engine,
	Speed: number
}

type Car = typeof( setmetatable({}, Car) )

export type Car = typeof( setmetatable({} :: self, Car) )

function Car.new(): Car
	local self = setmetatable({} :: self, Car)
	self._Engine = Engine.new()
	self.Speed = 15
	return self
end

function Car.Boost(self: Car): ()
	self.Speed += 50
end

return Car

Engine.lua

export type Car = typeof((function()
	local module = require(script.Parent)
	return {} :: typeof(module.new())
end)())

local Engine = {}
Engine.__index = Engine

type self = {
	Speed: number
}

type Engine = typeof( setmetatable({}, Engine) )

export type Engine = typeof( setmetatable({} :: self, Engine) )

function Engine.new(Car : Car): Engine
	local self = setmetatable({} :: self, Engine)
	self.Speed = 15
	return self
end

return Engine

What am I missing?

Here in the parameter (Car : Car) just resolves to any type when it should resolve to Car type:

function Engine.new(Car : Car): Engine
	local self = setmetatable({} :: self, Engine)
	self.Speed = 15
	return self
end

More info: Guide to Type-Checking with OOP

@MagmaBurnsV posted about this method and I wanted to adopt it so that I can compose objects inside of each other. Anyone have any ideas please? Any help is appreciated, thanks!

You could establish a new module and put all your types into that module so it can be used across all your classes

*Edit

Also im quite confused why you would need to pass in the car class into the engine class as it isnt currently being used

I am having trouble understanding what you mean. Is this possible???

Types.lua (has the types):

local module = {}

local Engine = {}
Engine.__index = Engine

type EngineSelf = {
    HorsePower: number
}

type Engine = typeof(setmetatable({}, Engine))
export type Engine = typeof(setmetatable({} :: EngineSelf, Engine))

function Engine.new(): Engine
    local self = setmetatable({} :: EngineSelf, Engine)
    self.HorsePower = 15
    return self
end

module.Engine = Engine

local Car = {}
Car.__index = Car

type CarSelf = {
    _Engine: Engine,
    Speed: number
}

type Car = typeof(setmetatable({}, Car))
export type Car = typeof(setmetatable({} :: CarSelf, Car))

function Car.new(): Car
    local self = setmetatable({} :: CarSelf, Car)
    self._Engine = Engine.new()
    self.Speed = 15
    return self
end

function Car.Boost(self: Car): ()
    self.Speed += 50
end

module.Car = Car

return module

In Car.lua, how would I fetch the Engine type from that?

local Types = require(script.Parent.Types)
local Engine = require(script.Engine)

local Car = {}
Car.__index = Car

type self = {
	["_Engine"]: Engine,
	Speed: number
}

type Car = typeof( setmetatable({}, Car) )

export type Car = typeof( setmetatable({} :: self, Car) )

function Car.new(): Car
	local self = setmetatable({} :: self, Car)
	self._Engine = Engine.new()
	self.Speed = 15
	return self
end

function Car.Boost(self: Car): ()
	self.Speed += 50
end

return Car

It is a bit messy but it is a proof of concept. I am looking to compose objects in objects and just did that to test if it would work but I am trying to get it to work. What do you think of the above, can we do this to get the Types or did I do it wrong? Bit sloppy but I tried.

Sorry for the late response I kind of fell asleep

im pretty sure the Engine type would already be inside of car.lua if you used Engine.new() because Engine.new() returns an Engine object of the Engine type.

if your asking for the literal type you could just export the engine type

-- a module that holds all the types

export type Engine = {
    HorsePower: number
}

export type Car = {
    _Engine: Engine
    Speed: number
}

-- car module
-- if you want to fetch the engine type you could do it liike this

local types = require(--[[path to  type module]])
type Engine = types.Engine