luau icon indicating copy to clipboard operation
luau copied to clipboard

Parameter types with methods are different depending on `.` or `:` calling

Open jackdotink opened this issue 1 year ago • 1 comments

local Class = {}
Class.__index = Class

function Class.new<T>(Data: T)
	return setmetatable({ Data = Data }, Class)
end

type Class<T> = typeof(Class.new((nil :: any) :: T))

function Class.Update<T>(self: Class<T>, Update: (T) -> T)
	self.Data = Update(self.Data)
end

function Class.Get<T>(self: Class<T>): T
	return self.Data
end

local inst = Class.new({
	Text = "Hello, World",
})

inst:Update(function(Data)
	-- Type of Data is `a` here - incorrect behavior
	return Data
end)

inst.Update(inst, function(Data)
	-- Type of Data is `{ Text: string }` here - correct behavior
	return Data
end)

local value = inst:Get()
-- Type of value is `{ Text: string }` here

Depending on if Update is called using a . or : the types of the parameters change - specifically when using generics. The Get example shows how this doesn't apply to returns, just parameters.

jackdotink avatar Aug 16 '23 12:08 jackdotink

I don't believe the types changing between using : or . with the same self object is intentional.

jackdotink avatar Aug 27 '23 04:08 jackdotink

typing skill issue

--!strict

local class = {}
class.__index = class

type class<T> = {
  __index: class<T>,
  new: (Data: T) -> Widget<T>,
  Update: (self: Widget<T>, Update: (T) -> T) -> (),
}

export type Widget<T> = typeof(setmetatable({} :: {}, class :: class<T>))

function class.new<T>(Data: T): Widget<T>
  return setmetatable({
    Data = Data
  }, class :: class<T>)
end

function class:Update<T>(Update: (T) -> T)
  self.Data = Update(self.Data)
end

local object = class.new(
  {
    Text = "Hello, World!"
  }
)

object:Update(function(Data)
    return Data -- Data is not 'a' here but {Text: string} - correct behaviour
end)

image

daolgierd avatar Jun 03 '24 21:06 daolgierd

fixed by new solver

jackdotink avatar Jun 03 '24 21:06 jackdotink