Can't quite understand how type checking works

Hey! I’m beginning to dive into type checking not just for my own organizational skills, but so I can understand other scripts and how to dissect them for my personal understanding. Right now, I want to learn how to be able to alter values OUTSIDE of the module script using types so that things can be easier to read.

Here is what I am currently working on, I have an ability script that makes the module script fire and then the module itself.

Hitbox Starter: (Local Script)

local RS = game:GetService("ReplicatedStorage")
local UIS = game:GetService("UserInputService")

local hitboxModule = require(RS:WaitForChild("HitboxModule"))

UIS.InputBegan:Connect(function(input, gameProcessed)
	
	if gameProcessed then return end
	
	if input.KeyCode == Enum.KeyCode.Q then
		
		local hitbox = hitboxModule.CreateHitbox()
		hitbox.HitboxMode = "Constant"
		hitboxModule.StartHitbox()
		
	end
end)

Hitbox Module: (Module Script)

--!strict

local clientBox = {}
clientBox.__index = clientBox

export type Attributes = {
	
	HitboxMode : string
	
}

function clientBox.CreateHitbox()
	
	local self = setmetatable({} :: Attributes, clientBox)
	
	self.HitboxMode = "Default"
	--print(self)	
	
	return self
end

function clientBox.StartHitbox(self : Attributes)

	local mode = self.HitboxMode
	
	if mode == "Constant" then
		print("Mode is Constant")
	end

end

return clientBox

In this example, I want to be able to set the mode of the hitbox to, “Constant” and then have it print out what the current mode is and every time I try to test, I get either nil or an error regarding nil.


So how would I make, for the sake of this example, a simple module script where I create a hitbox, change some of the values via types and then have that value be reflected in another function? It’s a little more advanced than what I’m used to be as stated earlier, it’s something I’d like to understand to better my work!

The error you’re getting has nothing to do with types. You’re just not passing a reference to the instance of clientBox that the StartHitbox function expects. You can fix this in a few different ways:

  • In “Hitbox Starter”, pass in the reference to the StartHitbox function call
		local hitbox = hitboxModule.CreateHitbox()
		hitbox.HitboxMode = "Constant"
		hitboxModule.StartHitbox(hitbox)
  • Adjust the syntax to use the : operator - which absolves the need for an explicit self parameter
--In "Hitbox Module"
function clientBox:StartHitbox() --The type here isn't technically correct (I'll address later)
	local mode = self.HitboxNode
	if mode == "Constant" then
		print("Mode is Constant")
	end
end
--In "Hitbox Starter"
		local hitbox = hitboxModule.CreateHitbox()
		hitbox.HitboxMode = "Constant"
		hitbox:StartHitbox()

Types and type-checking especially for OOP / metatables is in a bit of a volatile state right now. There is a beta out called the “New Luau type solver” which attempts to mitigate some of the pain points with the current type solver. Under the beta, you can do something like this:

--!strict

local MyClass = {}
MyClass.__index = MyClass

export type MyClassInstance = setmetatable<{
	Name: string
}, typeof(MyClass)>

function MyClass.new(name: string): MyClassInstance
	
	local self = setmetatable({
		Name = name,
	}, MyClass)
	
	return self
end

function MyClass:PrintName()
	--[[
		NOTE: As of writing this post, the beta type solver can act strange about the type of `self`
		A band-aid fix at the moment is to reassign self as a local variable and cast, like the line below
	]]
	local self = self :: MyClassInstance
	print(self.Name)
end

return MyClass

(See here for the method without the beta type solver)

2 Likes

You did not call StartHitbox correctly. Probably you called it with a . instead of a : since self is nil instead of being the first argument.

1 Like

Ye so basically you got smth like this
Module:

local module = {}
module.__index = module

function module.new(data)
local self = setmetatable({}, module)
self.data = data
return self
end

function module:doSomething()
local data = self.data
...
end

Handler:

local module = require(...)
local object = module.new(data)
object:doSomething()
print(object)
1 Like

Thanks for taking your time to explain it, the changes you’ve made make more sense to me now than what they did before!

Currently however, I am trying your 2nd solution, (changing the . to the : in the specified spots) but whenever I attempt to print mode from the start hitbox function, it is returning nil and not printing the, “Mode is constant” print statement either. I believe I wrote it the same exact way yes?

local RS = game:GetService("ReplicatedStorage")
local UIS = game:GetService("UserInputService")

local hitboxModule = require(RS:WaitForChild("HitboxModule"))

UIS.InputBegan:Connect(function(input, gameProcessed)
	
	if gameProcessed then return end
	
	if input.KeyCode == Enum.KeyCode.Q then
		
		local hitbox = hitboxModule.CreateHitbox() --East98 Solution
		hitbox.HitboxMode = "Constant"
		hitbox:StartHitbox()
		
	end
end)
--!strict

local clientBox = {}
clientBox.__index = clientBox

export type Attributes = {
	
	HitboxMode : string
	
}

function clientBox.CreateHitbox()
	
	local self = setmetatable({} :: Attributes, clientBox)
	
	self.HitboxMode = "Default"
	--print(self)	
	
	return self
end

function clientBox:StartHitbox()  --East98 solution
	local mode = self.HitboxNode
	
	print(mode)
	
	if mode == "Constant" then
		
		print("Mode is Constant")
		
	end
end
return clientBox


I don’t know what else I’m missing about this.

1 Like

Looks like you wrote self.HitboxNode instead of self.HitboxMode in the StartHitbox method.

2 Likes

I realized that write after I wrote it so lets just ignore that pft.

But regardless, thanks a ton!

Hey, glad I could help a bit too, but next time give the solution too @East98, he really deserves it. Good luck on your game and have a nice day!

2 Likes

Oh I thought I did, thanks for catching that I will change it real quick!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.