Signal.new()返回Signal类型失败,类型转换报错求助
解决Luau严格模式下Signal.new()的类型转换错误
问题重现
尝试通过Signal.new()返回Signal对象时触发类型错误:
TypeError: Type '{ @metatable Signal, {| _callbacks: {| |}, _waiting: {| |} |} }' could not be converted into 'Signal'
即使使用:: Signal强制类型转换,仍提示:
Cannot cast '{ @metatable Signal, {| _callbacks: {| |}, _waiting: {| |} |} }' into 'Signal' because the types are unrelated
问题原因
在Luau的严格类型检查中,你定义的export type Signal是普通table类型,而setmetatable返回的是带元表的table,类型系统会将这两者视为完全独立的类型,因此直接强制转换会失败。
解决方案
调整Signal类型定义,明确标注它是带有指定元表的类型,让类型系统识别出setmetatable返回对象与Signal类型的关联。
修正后的完整代码
--!strict local Signal = {} Signal.__index = Signal export type Connection = { Disconnect: () -> (), } -- 调整类型定义,合并元表类型与成员类型 export type Signal = typeof(setmetatable({}, Signal)) & { _callbacks: { (any) -> () }, _waiting: { thread }, Connect: (self: Signal, callback: (any) -> ()) -> Connection, Disconnect: (self: Signal, callback: (any) -> ()) -> (), Fire: (self: Signal, ...any) -> (), Wait: (self: Signal) -> (...any), } function Signal.new(): Signal -- 无需强制类型转换,类型系统自动匹配 return setmetatable({ _callbacks = {}, _waiting = {}, }, Signal) end function Signal:Disconnect(Callback: (any) -> ()) local Callbacks = self._callbacks for Index, CallBack in Callbacks do if CallBack == Callback then table.remove(Callbacks, Index) return end end end function Signal:Connect(callback: (any) -> ()): Connection local Callbacks = self._callbacks Callbacks[#Callbacks+1] = callback return { Disconnect = function() Signal.Disconnect(self, callback) end } end function Signal:Fire(...: any) for _, Callback in self._callbacks do Callback(...) end for Index = #self._waiting, 1, -1 do task.spawn(self._waiting[Index], ...) self._waiting[Index] = nil end end function Signal:Wait(): (...any) local Thread = coroutine.running() self._waiting[#self._waiting+1] = Thread return coroutine.yield() end return Signal
关键修改点
- 类型定义合并:通过
typeof(setmetatable({}, Signal)) & { ... },将带有Signal元表的table类型与自定义的成员属性/方法类型合并,让类型系统正确识别setmetatable返回对象就是Signal类型。 - 移除冗余断言:修正类型定义后,
Signal.new()的返回值会自动匹配Signal类型,无需再添加:: Signal强制转换。
替代方案
如果不想使用typeof方式,也可以直接在类型定义中添加元表注解:
export type Signal = { @metatable Signal, _callbacks: { (any) -> () }, _waiting: { thread }, Connect: (self: Signal, callback: (any) -> ()) -> Connection, Disconnect: (self: Signal, callback: (any) -> ()) -> (), Fire: (self: Signal, ...any) -> (), Wait: (self: Signal) -> (...any), }
该方式同样能让类型系统识别出该类型对应带有Signal元表的table,效果与上述方案一致。
内容的提问来源于stack exchange,提问作者8sfr
相关产品推荐
相关产品推荐

