Skip to content

Commit

Permalink
Luau Type Improvements (#76)
Browse files Browse the repository at this point in the history
This PR makes some improvements to the existing Luau types, including:

Improves reuse of the Action type
Fixes contravariance issue with Store type
Allows thunks to be void returning
  • Loading branch information
jkelaty-rbx authored Oct 7, 2022
1 parent 8c8da37 commit a5002a3
Show file tree
Hide file tree
Showing 8 changed files with 27 additions and 16 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ roblox.toml
# Darklua
**/darklua*

# Analysis artifacts
sourcemap.json
globalTypes.d.lua

# Misc OS and editor files
.DS_Store
.vscode
Expand Down
10 changes: 5 additions & 5 deletions foreman.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tools]
rojo = { source = "rojo-rbx/rojo", version = "7.2.0" }
selene = { source = "Kampfkarren/selene", version = "0.21.1" }
stylua = { source = "JohnnyMorganz/StyLua", version = "0.15.1" }
luau-lsp = { source = "JohnnyMorganz/luau-lsp", version = "*" }
wally = { source = "UpliftGames/wally", version = "0.3.1" }
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" }
wally = { source = "UpliftGames/wally", version = "=0.3.1" }
1 change: 0 additions & 1 deletion src/loggerMiddleware.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
--!strict
-- We want to be able to override outputFunction in tests, so the shape of this
-- module is kind of unconventional.
--
Expand Down
6 changes: 4 additions & 2 deletions src/makeActionCreator.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@

local actions = require(script.Parent.types.actions)

export type Action<Type> = actions.Action<Type>

export type ActionCreator<Type, Action, Args...> = actions.ActionCreator<Type, Action, Args...>

local function makeActionCreator<Type, Action, Args...>(name: Type, fn: (Args...) -> Action): ActionCreator<Type, Action, Args...>
local function makeActionCreator<Type, Payload, Args...>(name: Type, fn: (Args...) -> Payload): ActionCreator<Type, Payload, Args...>
assert(type(name) == "string", "Bad argument #1: Expected a string name for the action creator")

assert(type(fn) == "function", "Bad argument #2: Expected a function that creates action objects")

return setmetatable({
name = name,
}, {
__call = function(_self: any, ...: Args...): Action & { type: Type }
__call = function(_self: any, ...: Args...): Payload & Action<Type>
local result = fn(...)

assert(type(result) == "table", "Invalid action: An action creator must return a table")
Expand Down
1 change: 0 additions & 1 deletion src/makeThunkMiddleware.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
--!strict
--[[
A middleware that allows for functions to be dispatched with an extra
argument for convenience. Functions will receive two arguments:
Expand Down
8 changes: 4 additions & 4 deletions src/types/actions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ export type Action<Type = any> = {
type: Type,
}

export type AnyAction = Action & {
export type AnyAction = {
[string]: any,
}
} & Action

export type ActionCreator<Type, Action, Args...> = typeof(setmetatable(
export type ActionCreator<Type, Payload, Args...> = typeof(setmetatable(
{} :: { name: Type },
{} :: { __call: (any, Args...) -> (Action & { type: Type }) }
{} :: { __call: (any, Args...) -> (Payload & Action<Type>) }
))

return nil
11 changes: 9 additions & 2 deletions src/types/store.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,15 @@ export type Dispatch<State = any> = IDispatch<Store<State>>
export type IStore<State, Dispatch> = {
dispatch: Dispatch,
getState: (self: IStore<State, Dispatch>) -> State,
destruct: (self: IStore<State, Dispatch>) -> (),
flush: (self: IStore<State, Dispatch>) -> (),

--[[
FIXME LUAU: Typing self as any here is a hack to skirt around
variance-related issues with tables. Read-write properties
should obviate the need for this workaround.
]]
destruct: (self: any) -> (),
flush: (self: any) -> (),

changed: RBXScriptSignal,
}
export type Store<State = any> = IStore<State, Dispatch<State>>
Expand Down
2 changes: 1 addition & 1 deletion src/types/thunks.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ local store = require(script.Parent.store)
type IStore<State, Dispatch> = store.IStore<State, Dispatch>
type IDispatch<Store> = store.IDispatch<Store>

export type IThunkAction<ReturnType, Store> = (store: Store) -> ReturnType
export type IThunkAction<ReturnType, Store> = ((store: Store) -> ReturnType) | ((store: Store) -> ())
export type ThunkAction<ReturnType, State = any> = IThunkAction<ReturnType, ThunkfulStore<State>>

export type IThunkDispatch<Store> = <ReturnType>(
Expand Down

0 comments on commit a5002a3

Please sign in to comment.