Skip to content

Commit bc2ba8f

Browse files
Merge pull request cerebral#57 from cerebral/composition
feat(overmind): improve typing of actions, also allowing output
2 parents 1709c40 + cf615a2 commit bc2ba8f

File tree

14 files changed

+71
-68
lines changed

14 files changed

+71
-68
lines changed

packages/demos/todomvc/src/app/actions.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@ import * as mutations from './mutations'
77
type ChangeEvent = React.ChangeEvent<HTMLInputElement>
88

99
export const changeNewTodoTitle: Action<ChangeEvent> = (action) =>
10-
action<ChangeEvent>()
10+
action()
1111
.map(operations.getEventValue)
1212
.mutation(mutations.setNewTodoTitle)
1313

1414
export const addTodo: Action<React.FormEvent> = (action) =>
15-
action<React.FormEvent>()
15+
action()
1616
.do(operations.preventEventDefault)
1717
.mutation(mutations.addTodo)
1818
.mutation(mutations.clearNewTodoTitle)
1919
.map(() => Promise.resolve())
2020
.map(() => Promise.resolve())
2121

2222
export const toggleCompleted: Action<Todo> = (action) =>
23-
action<Todo>().mutation(mutations.toggleCompleted)
23+
action().mutation(mutations.toggleCompleted)

packages/demos/todomvc/src/app/index.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,16 @@ const config = {
1818

1919
type Config = TConfig<typeof config>
2020

21-
export type Action<Value = void> = TAction<Value, Config>
21+
export type Action<Input = void, Output = any> = TAction<Input, Output, Config>
2222
export type Derive = TDerive<Config>
23-
export type Compute<Value> = TCompute<Value, Config>
24-
export type Mutation<Value = any> = TOperation.Mutation<Value, Config>
25-
export type Do<Value = any> = TOperation.Do<Value, Config>
26-
export type Filter<Value = any> = TOperation.Filter<Value, Config>
27-
export type When<Value = any> = TOperation.When<Value, Config>
28-
export type Fork<Value = any> = TOperation.Fork<Value, Config>
29-
export type Map<Value, ReturnValue> = TOperation.Map<Value, ReturnValue, Config>
30-
export type Try<Value, ReturnValue> = TOperation.Try<Value, ReturnValue, Config>
23+
export type Compute<Input> = TCompute<Input, Config>
24+
export type Mutation<Input = any> = TOperation.Mutation<Input, Config>
25+
export type Do<Input = any> = TOperation.Do<Input, Config>
26+
export type Filter<Input = any> = TOperation.Filter<Input, Config>
27+
export type When<Input = any> = TOperation.When<Input, Config>
28+
export type Fork<Input = any> = TOperation.Fork<Input, Config>
29+
export type Map<Input, Output> = TOperation.Map<Input, Output, Config>
30+
export type Try<Input, Output> = TOperation.Try<Input, Output, Config>
3131

3232
const app = new App(config, {
3333
devtools: 'localhost:1234',

packages/node_modules/overmind-devtools/src/app/actions.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as operations from './operations'
44
import { Message, Tab } from './state'
55

66
const onMessage: Action<Message> = (action) =>
7-
action<Message>()
7+
action()
88
.mutation(mutations.performMutationsByMessageType)
99
.mutation(mutations.addMessagesFromClient)
1010

@@ -20,10 +20,10 @@ export const loadDevtools: Action = (action) =>
2020
.do(operations.connectCurrentPort(onMessage(action)))
2121

2222
export const setError: Action<string> = (action) =>
23-
action<string>().mutation(mutations.setError)
23+
action().mutation(mutations.setError)
2424

2525
export const changeNewPortValue: Action<string> = (action) =>
26-
action<string>()
26+
action()
2727
.map(operations.toNumber)
2828
.mutation(mutations.setNewPortValue)
2929

@@ -37,13 +37,13 @@ export const addPort: Action = (action) =>
3737
.do(operations.connectCurrentPort(onMessage))
3838

3939
export const changeTab: Action<Tab> = (action) =>
40-
action<Tab>().mutation(mutations.changeTab)
40+
action().mutation(mutations.changeTab)
4141

4242
export const toggleExpandState: Action<string[]> = (action) =>
43-
action<string[]>().mutation(mutations.toggleExpandStatePath)
43+
action().mutation(mutations.toggleExpandStatePath)
4444

4545
export const selectAction: Action<string> = (action) =>
46-
action<string>()
46+
action()
4747
.mutation(mutations.toggleActionItemCollapse)
4848
.mutation(mutations.selectAction)
4949

@@ -52,7 +52,7 @@ type Collapsed = {
5252
}
5353

5454
export const toggleCollapsed: Action<Collapsed> = (action) =>
55-
action<Collapsed>().mutation(mutations.toggleCollapsed)
55+
action().mutation(mutations.toggleCollapsed)
5656

5757
export const configurePort: Action = (action) =>
5858
action().mutation(mutations.configurePort)
@@ -69,6 +69,6 @@ export const removeApp: Action = (action) =>
6969
.do(operations.connectCurrentPort(onMessage(action)))
7070

7171
export const selectPort: Action<string> = (action) =>
72-
action<string>()
72+
action()
7373
.mutation(mutations.selectPort)
7474
.do(operations.connectCurrentPort(onMessage(action)))

packages/node_modules/overmind-devtools/src/app/index.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ const config = {
1717

1818
type Config = TConfig<typeof config>
1919

20-
export type Action<Value = void> = TAction<Value, Config>
20+
export type Action<Input = void, Output = any> = TAction<Input, Output, Config>
2121
export type Derive = TDerive<Config>
22-
export type Mutation<Value = any> = TOperation.Mutation<Value, Config>
23-
export type Do<Value = any> = TOperation.Do<Value, Config>
24-
export type Filter<Value = any> = TOperation.Filter<Value, Config>
25-
export type When<Value = any> = TOperation.When<Value, Config>
26-
export type Fork<Value = any> = TOperation.Fork<Value, Config>
27-
export type Map<Value, ReturnValue> = TOperation.Map<Value, ReturnValue, Config>
28-
export type Try<Value, ReturnValue> = TOperation.Try<Value, ReturnValue, Config>
22+
export type Mutation<Input = any> = TOperation.Mutation<Input, Config>
23+
export type Do<Input = any> = TOperation.Do<Input, Config>
24+
export type Filter<Input = any> = TOperation.Filter<Input, Config>
25+
export type When<Input = any> = TOperation.When<Input, Config>
26+
export type Fork<Input = any> = TOperation.Fork<Input, Config>
27+
export type Map<Input, Output> = TOperation.Map<Input, Output, Config>
28+
export type Try<Input, Output> = TOperation.Try<Input, Output, Config>
2929

3030
const app = new App(config)
3131

packages/node_modules/overmind/src/computed.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ describe('Computed', () => {
8080
state: typeof config.state
8181
actions: typeof config.actions
8282
}>
83-
type Action<Value = void> = TAction<Value, Config>
83+
type Action<Input = void, Output = any> = TAction<Input, Output, Config>
8484

8585
const app = new App(config)
8686
app.state.test(123)

packages/node_modules/overmind/src/derived.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ describe('Derived', () => {
3232
state: typeof config.state
3333
actions: typeof config.actions
3434
}>
35-
type Action<Value = void> = TAction<Value, Config>
35+
type Action<Input = void, Output = any> = TAction<Input, Output, Config>
3636

3737
const app = new App(config)
3838
function render() {

packages/node_modules/overmind/src/index.test.ts

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,7 @@ describe('Overmind', () => {
1414
})
1515
test('should instantiate app with actions', () => {})
1616
test('should instantiate app with namespaces', () => {
17-
const fooAction: Action<string> = (action) =>
18-
action<string>()
19-
.mutation((state) => state.foo.foo)
20-
.do((effects) => effects)
17+
const fooAction: Action<string> = (action) => action()
2118

2219
const foo = {
2320
state: {
@@ -46,7 +43,7 @@ describe('Overmind', () => {
4643
}
4744
}>
4845

49-
type Action<Value = void> = TAction<Value, Config>
46+
type Action<Input = void, Output = any> = TAction<Input, Output, Config>
5047

5148
const config = {
5249
namespaces: {
@@ -129,7 +126,7 @@ describe('OPERATORS', () => {
129126
type Config = TConfig<{
130127
actions: typeof config.actions
131128
}>
132-
type Action<Value = void> = TAction<Value, Config>
129+
type Action<Input = void, Output = any> = TAction<Input, Output, Config>
133130

134131
const app = new App(config)
135132

@@ -151,7 +148,7 @@ describe('OPERATORS', () => {
151148
state: typeof config.state
152149
actions: typeof config.actions
153150
}>
154-
type Action<Value = void> = TAction<Value, Config>
151+
type Action<Input = void, Output = any> = TAction<Input, Output, Config>
155152

156153
const app = new App(config)
157154

@@ -162,7 +159,7 @@ describe('OPERATORS', () => {
162159
test('do', () => {
163160
expect.assertions(2)
164161
const doThis: Action<string> = (action) =>
165-
action<string>().do(({ foo }) => {
162+
action().do(({ foo }) => {
166163
expect(foo.bar()).toBe('baz')
167164
})
168165
const config = {
@@ -183,15 +180,15 @@ describe('OPERATORS', () => {
183180
effects: typeof config.effects
184181
actions: typeof config.actions
185182
}>
186-
type Action<Value = void> = TAction<Value, Config>
183+
type Action<Input = void, Output = any> = TAction<Input, Output, Config>
187184

188185
const app = new App(config)
189186
expect(app.actions.doThis('foo')).toBe('foo')
190187
})
191188
test('map', () => {
192189
expect.assertions(1)
193190
const doThis: Action<string> = (action) =>
194-
action<string>().map((_, value) => {
191+
action().map((_, value) => {
195192
return value.toUpperCase()
196193
})
197194
const config = {
@@ -202,7 +199,7 @@ describe('OPERATORS', () => {
202199
type Config = TConfig<{
203200
actions: typeof config.actions
204201
}>
205-
type Action<Value = void> = TAction<Value, Config>
202+
type Action<Input = void, Output = any> = TAction<Input, Output, Config>
206203

207204
const app = new App(config)
208205

@@ -224,7 +221,7 @@ describe('OPERATORS', () => {
224221
type Config = TConfig<{
225222
actions: typeof config.actions
226223
}>
227-
type Action<Value = void> = TAction<Value, Config>
224+
type Action<Input = void, Output = any> = TAction<Input, Output, Config>
228225
const app = new App(config)
229226

230227
return Promise.resolve(app.actions.doThis()).then((value) => {
@@ -247,7 +244,7 @@ describe('OPERATORS', () => {
247244
type Config = TConfig<{
248245
actions: typeof config.actions
249246
}>
250-
type Action<Value = void> = TAction<Value, Config>
247+
type Action<Input = void, Output = any> = TAction<Input, Output, Config>
251248
const app = new App(config)
252249
return Promise.resolve(app.actions.doThis()).then((value) => {
253250
expect(value).toBe('bar')
@@ -268,7 +265,7 @@ describe('OPERATORS', () => {
268265
type Config = TConfig<{
269266
actions: typeof config.actions
270267
}>
271-
type Action<Value = void> = TAction<Value, Config>
268+
type Action<Input = void, Output = any> = TAction<Input, Output, Config>
272269
const app = new App(config)
273270
expect(app.actions.doThis()).toBe('foo')
274271
})
@@ -288,7 +285,7 @@ describe('OPERATORS', () => {
288285
type Config = TConfig<{
289286
actions: typeof config.actions
290287
}>
291-
type Action<Value = void> = TAction<Value, Config>
288+
type Action<Input = void, Output = any> = TAction<Input, Output, Config>
292289
const app = new App(config)
293290

294291
expect(app.actions.doThis()).toBe('bar')
@@ -297,7 +294,7 @@ describe('OPERATORS', () => {
297294
test('filter - true', () => {
298295
expect.assertions(1)
299296
const doThis: Action<string> = (action) =>
300-
action<string>()
297+
action()
301298
.filter(() => true)
302299
.map(() => 'bar')
303300
const config = {
@@ -308,14 +305,14 @@ describe('OPERATORS', () => {
308305
type Config = TConfig<{
309306
actions: typeof config.actions
310307
}>
311-
type Action<Value = void> = TAction<Value, Config>
308+
type Action<Input = void, Output = any> = TAction<Input, Output, Config>
312309
const app = new App(config)
313310
expect(app.actions.doThis('foo')).toBe('bar')
314311
})
315312
test('filter - false', () => {
316313
expect.assertions(1)
317314
const doThis: Action<string> = (action) =>
318-
action<string>()
315+
action()
319316
.filter(() => false)
320317
.map(() => 'bar')
321318
const config = {
@@ -326,7 +323,7 @@ describe('OPERATORS', () => {
326323
type Config = TConfig<{
327324
actions: typeof config.actions
328325
}>
329-
type Action<Value = void> = TAction<Value, Config>
326+
type Action<Input = void, Output = any> = TAction<Input, Output, Config>
330327
const app = new App(config)
331328

332329
expect(app.actions.doThis('foo')).toEqual({ value: 'foo' })
@@ -350,7 +347,7 @@ describe('OPERATORS', () => {
350347
type Config = TConfig<{
351348
actions: typeof config.actions
352349
}>
353-
type Action<Value = void> = TAction<Value, Config>
350+
type Action<Input = void, Output = any> = TAction<Input, Output, Config>
354351
const app = new App(config)
355352

356353
return Promise.resolve(app.actions.doThis()).then((value) => {

packages/node_modules/overmind/src/index.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -157,20 +157,30 @@ export interface Events {
157157

158158
export type ActionCallback<App> = (action: TActionCreator<App>) => any
159159

160-
export type TAction<InitialValue, App> = (
161-
action: TActionCreator<App>
160+
export type TAction<InitialValue, ReturnValue, App> = (
161+
action: () => [InitialValue] extends [void]
162+
? INoValueAction<
163+
TConfig<App>['state'],
164+
TConfig<App>['effects'] & { state: TConfig<App>['state'] },
165+
any
166+
>
167+
: IValueAction<
168+
TConfig<App>['state'],
169+
TConfig<App>['effects'] & { state: TConfig<App>['state'] },
170+
any
171+
>
162172
) => [InitialValue] extends [void]
163173
? INoValueAction<
164174
TConfig<App>['state'],
165175
TConfig<App>['effects'] & { state: TConfig<App>['state'] },
166176
InitialValue,
167-
any
177+
ReturnValue
168178
>
169179
: IValueAction<
170180
TConfig<App>['state'],
171181
TConfig<App>['effects'] & { state: TConfig<App>['state'] },
172182
InitialValue,
173-
any
183+
ReturnValue
174184
>
175185

176186
export type TActionCreator<App> = {
@@ -242,14 +252,10 @@ export default class App<
242252
eventHub: EventEmitter<Events>
243253
devtools: Devtools
244254
actions: {
245-
[T in keyof EvalConfig['actions']]: EvalConfig['actions'][T] extends ActionCallback<
246-
EvalConfig
247-
>
255+
[T in keyof EvalConfig['actions']]: EvalConfig['actions'][T] extends Function
248256
? ReturnType<EvalConfig['actions'][T]>
249257
: {
250-
[P in keyof EvalConfig['actions'][T]]: EvalConfig['actions'][T][P] extends ActionCallback<
251-
EvalConfig
252-
>
258+
[P in keyof EvalConfig['actions'][T]]: EvalConfig['actions'][T][P] extends Function
253259
? ReturnType<EvalConfig['actions'][T][P]>
254260
: undefined
255261
}

packages/node_modules/overmind/src/reaction.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ describe('Reaction', () => {
2828
actions: typeof config.actions
2929
reactions: typeof config.reactions
3030
}>
31-
type Action<Value = void> = TAction<Value, Config>
31+
type Action<Input = void, Output = any> = TAction<Input, Output, Config>
3232
type Reaction = TReaction<Config>
3333
const app = new App(config)
3434

@@ -66,7 +66,7 @@ describe('Reaction', () => {
6666
actions: typeof config.actions
6767
reactions: typeof config.reactions
6868
}>
69-
type Action<Value = void> = TAction<Value, Config>
69+
type Action<Input = void, Output = any> = TAction<Input, Output, Config>
7070
type Reaction = TReaction<Config>
7171
const app = new App(config)
7272
app.actions.foo()

packages/overmind-website/examples/api/action.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export const ts = [
1313
{
1414
code: `
1515
export const doThis: Action<number> = action =>
16-
action<number>()
16+
action()
1717
.map(operations.getUser)
1818
.mutation(mutations.setUser)
1919
`,

0 commit comments

Comments
 (0)