You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

关键修改点

  1. 类型定义合并:通过typeof(setmetatable({}, Signal)) & { ... },将带有Signal元表的table类型与自定义的成员属性/方法类型合并,让类型系统正确识别setmetatable返回对象就是Signal类型。
  2. 移除冗余断言:修正类型定义后,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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 21:42:38