Skip to content

Commit 9c5d5ce

Browse files
committed
introduce ReducerAsyncState type, type promise as optional undefined
1 parent d709416 commit 9c5d5ce

File tree

5 files changed

+73
-25
lines changed

5 files changed

+73
-25
lines changed

packages/react-async/src/Async.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import {
1313
FulfilledChildren,
1414
SettledChildren,
1515
RejectedChildren,
16-
AbstractState,
1716
AsyncAction,
17+
ReducerAsyncState,
1818
} from "./types"
1919

2020
interface InitialProps<T> {
@@ -112,7 +112,10 @@ export const createInstance = <T extends {}>(
112112
const { devToolsDispatcher } = globalScope.__REACT_ASYNC__
113113
const _reducer = props.reducer || defaultProps.reducer
114114
const _dispatcher = props.dispatcher || defaultProps.dispatcher || devToolsDispatcher
115-
const reducer: (state: AsyncState<T>, action: AsyncAction<T>) => AsyncState<T> = _reducer
115+
const reducer: (
116+
state: ReducerAsyncState<T>,
117+
action: AsyncAction<T>
118+
) => ReducerAsyncState<T> = _reducer
116119
? (state, action) => _reducer(state, action, asyncReducer)
117120
: asyncReducer
118121
const dispatch = dispatchMiddleware<T>((action, callback) => {

packages/react-async/src/helpers.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,23 @@ import {
99
SettledChildren,
1010
AsyncState,
1111
AbstractState,
12+
AsyncInitial,
13+
AsyncFulfilled,
14+
AsyncPending,
15+
AsyncRejected,
1216
} from "./types"
1317

1418
/**
1519
* Due to https://github.com/microsoft/web-build-tools/issues/1050, we need
1620
* AbstractState imported in this file, even though it is only used implicitly.
1721
* This _uses_ AbstractState so it is not accidentally removed by someone.
1822
*/
19-
declare type ImportWorkaround<T> = AbstractState<T>
23+
declare type ImportWorkaround<T> =
24+
| AbstractState<T>
25+
| AsyncInitial<T>
26+
| AsyncFulfilled<T>
27+
| AsyncPending<T>
28+
| AsyncRejected<T>
2029

2130
type ChildrenFn = (...args: any[]) => React.ReactNode
2231
const renderFn = (children: React.ReactNode | ChildrenFn, ...args: any[]) => {

packages/react-async/src/reducer.ts

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import {
88
AsyncRejected,
99
AsyncInitial,
1010
AbstractState,
11+
ReducerAsyncState,
12+
ReducerBaseState,
1113
} from "./types"
1214

1315
/**
@@ -32,20 +34,20 @@ export const init = <T>({
3234
initialValue?: Error | T
3335
promise?: Promise<T>
3436
promiseFn?: PromiseFn<T>
35-
}): AsyncState<T> => ({
36-
initialValue,
37-
data: initialValue instanceof Error ? undefined : initialValue,
38-
error: initialValue instanceof Error ? initialValue : undefined,
39-
value: initialValue,
40-
startedAt: promise || promiseFn ? new Date() : undefined,
41-
finishedAt: initialValue ? new Date() : undefined,
42-
...getStatusProps(getInitialStatus(initialValue, promise || promiseFn)),
43-
counter: 0,
44-
// @ts-ignore see #92
45-
promise: undefined,
46-
})
37+
}) =>
38+
({
39+
initialValue,
40+
data: initialValue instanceof Error ? undefined : initialValue,
41+
error: initialValue instanceof Error ? initialValue : undefined,
42+
value: initialValue,
43+
startedAt: promise || promiseFn ? new Date() : undefined,
44+
finishedAt: initialValue ? new Date() : undefined,
45+
...getStatusProps(getInitialStatus(initialValue, promise || promiseFn)),
46+
counter: 0,
47+
promise: undefined,
48+
} as ReducerAsyncState<T>)
4749

48-
export const reducer = <T>(state: AsyncState<T>, action: AsyncAction<T>) => {
50+
export const reducer = <T>(state: ReducerAsyncState<T>, action: AsyncAction<T>) => {
4951
switch (action.type) {
5052
case actionTypes.start:
5153
return {
@@ -55,7 +57,7 @@ export const reducer = <T>(state: AsyncState<T>, action: AsyncAction<T>) => {
5557
...getStatusProps(statusTypes.pending),
5658
counter: action.meta.counter,
5759
promise: action.meta.promise,
58-
} as AsyncPending<T>
60+
} as AsyncPending<T, ReducerBaseState<T>>
5961
case actionTypes.cancel:
6062
return {
6163
...state,
@@ -64,7 +66,10 @@ export const reducer = <T>(state: AsyncState<T>, action: AsyncAction<T>) => {
6466
...getStatusProps(getIdleStatus(state.error || state.data)),
6567
counter: action.meta.counter,
6668
promise: action.meta.promise,
67-
} as AsyncInitial<T> | AsyncFulfilled<T> | AsyncRejected<T>
69+
} as
70+
| AsyncInitial<T, ReducerBaseState<T>>
71+
| AsyncFulfilled<T, ReducerBaseState<T>>
72+
| AsyncRejected<T, ReducerBaseState<T>>
6873
case actionTypes.fulfill:
6974
return {
7075
...state,
@@ -74,7 +79,7 @@ export const reducer = <T>(state: AsyncState<T>, action: AsyncAction<T>) => {
7479
finishedAt: new Date(),
7580
...getStatusProps(statusTypes.fulfilled),
7681
promise: action.meta.promise,
77-
} as AsyncFulfilled<T>
82+
} as AsyncFulfilled<T, ReducerBaseState<T>>
7883
case actionTypes.reject:
7984
return {
8085
...state,
@@ -83,7 +88,7 @@ export const reducer = <T>(state: AsyncState<T>, action: AsyncAction<T>) => {
8388
finishedAt: new Date(),
8489
...getStatusProps(statusTypes.rejected),
8590
promise: action.meta.promise,
86-
} as AsyncRejected<T>
91+
} as AsyncRejected<T, ReducerBaseState<T>>
8792
default:
8893
return state
8994
}

packages/react-async/src/types.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ export interface AsyncOptions<T> {
4040
onResolve?: (data: T) => void
4141
onReject?: (error: Error) => void
4242
reducer?: (
43-
state: AsyncState<T>,
43+
state: ReducerAsyncState<T>,
4444
action: AsyncAction<T>,
45-
internalReducer: (state: AsyncState<T>, action: AsyncAction<T>) => AsyncState<T>
45+
internalReducer: (state: ReducerAsyncState<T>, action: AsyncAction<T>) => ReducerAsyncState<T>
4646
) => AsyncState<T>
4747
dispatcher?: (
4848
action: AsyncAction<T>,
@@ -60,7 +60,7 @@ export interface AsyncProps<T> extends AsyncOptions<T> {
6060
export interface AbstractState<T> {
6161
initialValue?: T | Error
6262
counter: number
63-
promise: Promise<T>
63+
promise: Promise<T> | undefined
6464
run: (...args: any[]) => void
6565
reload: () => void
6666
cancel: () => void
@@ -129,8 +129,17 @@ export type AsyncRejected<T, S = AbstractState<T>> = S & {
129129
isRejected: true
130130
isSettled: true
131131
}
132-
export type AsyncState<T, S extends AbstractState<T> = AbstractState<T>> =
132+
133+
type BaseAsyncState<T, S> =
133134
| AsyncInitial<T, S>
134135
| AsyncPending<T, S>
135136
| AsyncFulfilled<T, S>
136137
| AsyncRejected<T, S>
138+
139+
export type ReducerBaseState<T> = Omit<
140+
AbstractState<T>,
141+
"run" | "reload" | "cancel" | "setData" | "setError"
142+
>
143+
export type ReducerAsyncState<T> = BaseAsyncState<T, ReducerBaseState<T>>
144+
145+
export type AsyncState<T, S extends AbstractState<T> = AbstractState<T>> = BaseAsyncState<T, S>

packages/react-async/src/useAsync.tsx

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,29 @@ import { useCallback, useDebugValue, useEffect, useMemo, useRef, useReducer } fr
33
import globalScope from "./globalScope"
44
import { actionTypes, init, dispatchMiddleware, reducer as asyncReducer } from "./reducer"
55

6-
import { AsyncOptions, AsyncState, AbstractState, PromiseFn, Meta } from "./types"
6+
import {
7+
AsyncOptions,
8+
AsyncState,
9+
AbstractState,
10+
PromiseFn,
11+
Meta,
12+
AsyncInitial,
13+
AsyncFulfilled,
14+
AsyncPending,
15+
AsyncRejected,
16+
} from "./types"
17+
18+
/**
19+
* Due to https://github.com/microsoft/web-build-tools/issues/1050, we need
20+
* AbstractState imported in this file, even though it is only used implicitly.
21+
* This _uses_ AbstractState so it is not accidentally removed by someone.
22+
*/
23+
declare type ImportWorkaround<T> =
24+
| AbstractState<T>
25+
| AsyncInitial<T>
26+
| AsyncFulfilled<T>
27+
| AsyncPending<T>
28+
| AsyncRejected<T>
729

830
export interface FetchOptions<T> extends AsyncOptions<T> {
931
defer?: boolean

0 commit comments

Comments
 (0)