How to assert typeof a generic?

I’m trying to implement a stack data structure.

It will be single type: for example:

  • a stack of numbers
  • a stack of brick colors
  • a stack of booelans

Because of this, I use the < T > generic in my “Types” module: (the stack is built upon tables, contents is just what is in the stack at any point)

--!strict

local Types = {}

export type Stack<T> = {
	contents: {T},
	max_size: number,
}

return Types

Then I have a stack methods module. One of the functions here is “push”, which will accept two parameters: A stack and some data to be pushed onto said stack.
However, when the function first runs, I want to make sure that the types of the parameters are what they should be. This was quite trivial with checking the stack objects contents field and max_size field, but I’m struggling checking the type of the data parameter.

Essentially, if I pass in a stack of numbers, the data I try to push should also be a number.
But if I pass in a stack of strings, the data I try to push should be a string.

--!strict
-- Services
local ServerScriptService = game:GetService("ServerScriptService")

-- Modules
local Types = require(ServerScriptService.Types)


local StackMethods = {}

function StackMethods.push<T>(stack_object: Types.Stack<T>, data: T)
	-- Check the parameters are of the correct type
	assert(typeof(stack_object.contents) == "table", "Expected table for stack contents, recieved: "..typeof(stack_object.contents))
	assert(typeof(stack_object.max_size) == "number", "Expected number for stack max size, recieved: "..typeof(stack_object.max_size))
	
	assert(typeof(data) == T) -- Cant get this to work!!!!!!!!!!!!!!!!!
	
end

return StackMethods

Currently, the linter is saying “Unknown global ‘T’”

So how could I throw an error if the type of data wasn’t T?

I don’t believe that you need to do any checks for the type. The function only takes in T, so it makes no sense to be checking whether data is T, when it always will be.

2 Likes

I do need to check the type since an error isn’t thrown if there is a type mismatch.

For example:
image

This should throw an error, since I’m trying to push a string onto a stack of numbers.

And yet:
image

Like I said, it works fine for these lines:

I just can’t work out the syntax for this
image

And I’ve not been able to find much online either

1 Like

I think the issue here is that data is setting the type of the function as its the only variable typed as T.

I also got the assert working.

local generic: T = typeof(data)
assert(typeof(data) == typeof(generic))

But again, this is redundant because it’s confirming that the type of data is equal to the type of data.

Luau type checking is static, so it’s not possible to do what you’re trying to do without using some runtime type checking library like t. However, this would make implementation quite a bit messier because the stacks would need to store the typecheck function.

export type Stack<T> = {
	contents: { T },
	max_size: number,

	-- Would need to add this:
	verifier: (any) -> boolean,
}

-- e.g. newStack(128, t.string) if you're using t
local function newStack<T>(maxSize: number, verifier: (any) -> boolean): Stack<T>
	return {
		contents = table.create(maxSize),
		max_size = maxSize,
		verifier = verifier,
	}
end

function StackMethods.push<T>(stack_object: Stack<T>, data: T)
	assert(
		typeof(stack_object.contents) == "table",
		"Expected table for stack contents, recieved: " .. typeof(stack_object.contents)
	)
	assert(
		typeof(stack_object.max_size) == "number",
		"Expected number for stack max size, recieved: " .. typeof(stack_object.max_size)
	)

	assert(stack_object.verifier(data))
end

That being said, it’s completely the user’s fault if they ignore the lint error. I don’t think trying to resolve this will be worth your time.

4 Likes

Thank you for the response.

I remember trying another field to verify the type, but I wouldn’t have thought of doing like this.

I think I’ll just go with this advice.

Thanks for the help!

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