This wasn’t submitted as an RFC since
require
is a Roblox-specific global. (yes require doesn’t exist in vanilla Luau)
The Problem:
As a Roblox developer it is currently very difficult to create relational references to modules, because require
uses magic that forces an exact path in the call.
There are a few boilerplate fixes, my current one is
fancyRequire(script.Parent.Module :: typeof(require(script.Parent.Module)))
… where fancyRequire is <T>(T): T
This doesn’t work yay.
However, this currently raises a type error, because obviously you cant cast Instance
to unknown
. The problem here is pretty obvious
Problem 1: Library loaders
Lets assume you want to make a function that loads a module in a special way, this would obviously require a function.
local function tryRequire(mod)
local s, e = pcall(require, mod)
if s then return e end
end
This code wont typecheck any modules passed into it, all returns will be asserted as any
, since the magic of require
gets lost as soon as it gets a function argument passed to it.
Problem 2: Loss of information in lists etc.
Again, the same problem arises, ModuleScripts lose their magic as soon as you put them in a list, see image:
The issue also arrises with string keys.
The Solution.
A new Module<T>
type to replace ModuleScript. (or even just use ModuleScript?), this would hold the magic return
value as T
, and then require can take it even if it’s given to a list, function argument etc.
The theoretical type of require would become require<T>(module: Module<T>): T
If Roblox were to address this issue it would improve my development experience since I wouldn’t need to rely on hacky types and type coercians to fix issues with the require
function.