diff --git a/CHANGELOG.md b/CHANGELOG.md index ba0230a..d791476 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # RoactRodux Changelog # Unreleased Changes +* Update function type checks to account for callable tables (like those returned by Rodux.makeActionCreator). + ## 0.5.1 (2022-05-20) * Expose StoreContext in public API (for use by hooks) ([#56](https://github.com/Roblox/roact-rodux/pull/56)) diff --git a/foreman.toml b/foreman.toml index 014faff..d7778b8 100644 --- a/foreman.toml +++ b/foreman.toml @@ -2,4 +2,4 @@ rojo = { source = "rojo-rbx/rojo", version = "=7.2.1" } selene = { source = "Kampfkarren/selene", version = "=0.21.1" } stylua = { source = "JohnnyMorganz/StyLua", version = "=0.15.1" } -luau-lsp = { source = "JohnnyMorganz/luau-lsp", version = "=1.8.1" } +luau-lsp = { source = "JohnnyMorganz/luau-lsp", version = "=1.33.1" } diff --git a/rotriever.toml b/rotriever.toml index f6bcc9d..dd9300c 100644 --- a/rotriever.toml +++ b/rotriever.toml @@ -3,7 +3,7 @@ name = "RoactRodux" authors = ["Roblox"] license = "Apache-2.0" content_root = "src" -version = "0.5.1" +version = "0.5.2" files = ["*", "!*.spec.lua"] [dependencies] diff --git a/src/connect.lua b/src/connect.lua index 1b467b8..33803d8 100644 --- a/src/connect.lua +++ b/src/connect.lua @@ -32,6 +32,15 @@ local function noop() return nil end +--[[ + Returns `true` if the value can be called i.e. you can write `value(...)`. +]] +local function isCallable(value: any): boolean + return type(value) == "function" + or (type(value) == "table" and getmetatable(value) and getmetatable(value).__call ~= nil) + or false +end + --[[ The stateUpdater accepts props when they update and computes the complete set of props that should be passed to the wrapped component. @@ -77,7 +86,7 @@ local function connect? ) if mapStateToPropsOrThunk ~= nil then - assert(typeof(mapStateToPropsOrThunk) == "function", "mapStateToProps must be a function or nil!") + assert(isCallable(mapStateToPropsOrThunk), "mapStateToProps must be a function or nil!") else mapStateToPropsOrThunk = noop end @@ -142,8 +151,8 @@ local function connect)( + (dispatch :: any) :: ThunkfulDispatchProp + ) + elseif mapDispatchType == "table" then mappedStoreDispatch = {} for key, actionCreator in pairs(mapDispatchToProps :: ActionCreatorMap) do - assert(typeof(actionCreator) == "function", "mapDispatchToProps must contain function values") + assert(isCallable(actionCreator), "mapDispatchToProps must contain function values") mappedStoreDispatch[key] = function(...) dispatch(actionCreator(...)) end end - elseif mapDispatchType == "function" then - mappedStoreDispatch = (mapDispatchToProps :: MapDispatchToProps)( - (dispatch :: any) :: ThunkfulDispatchProp - ) end local stateUpdater = makeStateUpdater(self.store) diff --git a/src/connect.spec.lua b/src/connect.spec.lua index e0c1628..ee0fb6d 100644 --- a/src/connect.spec.lua +++ b/src/connect.spec.lua @@ -53,6 +53,12 @@ return function() }) end) + it("should accept action creators that are callable tables", function() + connect(nil, { + foo = Rodux.makeActionCreator("Foo", function() end), + }) + end) + it("should throw if not passed a component", function() local selector = function(store) return {}