UNPKG

5.96 kBTypeScriptView Raw
1export declare type PromiseState = "pending" | "fulfilled" | "rejected";
2export declare const PENDING = "pending";
3export declare const FULFILLED = "fulfilled";
4export declare const REJECTED = "rejected";
5declare type CaseHandlers<U, T> = {
6 pending?: (t?: T) => U;
7 fulfilled?: (t: T) => U;
8 rejected?: (e: any) => U;
9};
10export interface IBasePromiseBasedObservable<T> extends PromiseLike<T> {
11 isPromiseBasedObservable: true;
12 case<U>(handlers: CaseHandlers<U, T>, defaultFulfilled?: boolean): U;
13}
14export declare type IPendingPromise<T> = {
15 readonly state: "pending";
16 readonly value: T | undefined;
17};
18export declare type IFulfilledPromise<T> = {
19 readonly state: "fulfilled";
20 readonly value: T;
21};
22export declare type IRejectedPromise = {
23 readonly state: "rejected";
24 readonly value: unknown;
25};
26export declare type IPromiseBasedObservable<T> = IBasePromiseBasedObservable<T> & (IPendingPromise<T> | IFulfilledPromise<T> | IRejectedPromise);
27/**
28 * `fromPromise` takes a Promise, extends it with 2 observable properties that track
29 * the status of the promise and returns it. The returned object has the following observable properties:
30 * - `value`: either the initial value, the value the Promise resolved to, or the value the Promise was rejected with. use `.state` if you need to be able to tell the difference.
31 * - `state`: one of `"pending"`, `"fulfilled"` or `"rejected"`
32 *
33 * And the following methods:
34 * - `case({fulfilled, rejected, pending})`: maps over the result using the provided handlers, or returns `undefined` if a handler isn't available for the current promise state.
35 *
36 * The returned object implements `PromiseLike<TValue>`, so you can chain additional `Promise` handlers using `then`. You may also use it with `await` in `async` functions.
37 *
38 * Note that the status strings are available as constants:
39 * `mobxUtils.PENDING`, `mobxUtils.REJECTED`, `mobxUtil.FULFILLED`
40 *
41 * fromPromise takes an optional second argument, a previously created `fromPromise` based observable.
42 * This is useful to replace one promise based observable with another, without going back to an intermediate
43 * "pending" promise state while fetching data. For example:
44 *
45 * @example
46 * \@observer
47 * class SearchResults extends React.Component {
48 * \@observable.ref searchResults
49 *
50 * componentDidUpdate(nextProps) {
51 * if (nextProps.query !== this.props.query)
52 * this.searchResults = fromPromise(
53 * window.fetch("/search?q=" + nextProps.query),
54 * // by passing, we won't render a pending state if we had a successful search query before
55 * // rather, we will keep showing the previous search results, until the new promise resolves (or rejects)
56 * this.searchResults
57 * )
58 * }
59 *
60 * render() {
61 * return this.searchResults.case({
62 * pending: (staleValue) => {
63 * return staleValue || "searching" // <- value might set to previous results while the promise is still pending
64 * },
65 * fulfilled: (value) => {
66 * return value // the fresh results
67 * },
68 * rejected: (error) => {
69 * return "Oops: " + error
70 * }
71 * })
72 * }
73 * }
74 *
75 * Observable promises can be created immediately in a certain state using
76 * `fromPromise.reject(reason)` or `fromPromise.resolve(value?)`.
77 * The main advantage of `fromPromise.resolve(value)` over `fromPromise(Promise.resolve(value))` is that the first _synchronously_ starts in the desired state.
78 *
79 * It is possible to directly create a promise using a resolve, reject function:
80 * `fromPromise((resolve, reject) => setTimeout(() => resolve(true), 1000))`
81 *
82 * @example
83 * const fetchResult = fromPromise(fetch("http://someurl"))
84 *
85 * // combine with when..
86 * when(
87 * () => fetchResult.state !== "pending",
88 * () => {
89 * console.log("Got ", fetchResult.value)
90 * }
91 * )
92 *
93 * // or a mobx-react component..
94 * const myComponent = observer(({ fetchResult }) => {
95 * switch(fetchResult.state) {
96 * case "pending": return <div>Loading...</div>
97 * case "rejected": return <div>Ooops... {fetchResult.value}</div>
98 * case "fulfilled": return <div>Gotcha: {fetchResult.value}</div>
99 * }
100 * })
101 *
102 * // or using the case method instead of switch:
103 *
104 * const myComponent = observer(({ fetchResult }) =>
105 * fetchResult.case({
106 * pending: () => <div>Loading...</div>,
107 * rejected: error => <div>Ooops.. {error}</div>,
108 * fulfilled: value => <div>Gotcha: {value}</div>,
109 * }))
110 *
111 * // chain additional handler(s) to the resolve/reject:
112 *
113 * fetchResult.then(
114 * (result) => doSomeTransformation(result),
115 * (rejectReason) => console.error('fetchResult was rejected, reason: ' + rejectReason)
116 * ).then(
117 * (transformedResult) => console.log('transformed fetchResult: ' + transformedResult)
118 * )
119 *
120 * @param origPromise The promise which will be observed
121 * @param oldPromise The previously observed promise
122 * @returns origPromise with added properties and methods described above.
123 */
124export declare function fromPromise<T>(origPromise: PromiseLike<T>, oldPromise?: IPromiseBasedObservable<T>): IPromiseBasedObservable<T>;
125export declare namespace fromPromise {
126 export const reject: <T>(reason: any) => IRejectedPromise & IBasePromiseBasedObservable<T>;
127 function resolveBase<T>(value: T): IFulfilledPromise<T> & IBasePromiseBasedObservable<T>;
128 function resolveBase<T>(value?: T): IFulfilledPromise<T | undefined> & IBasePromiseBasedObservable<T>;
129 export const resolve: typeof resolveBase;
130 export {};
131}
132/**
133 * Returns true if the provided value is a promise-based observable.
134 * @param value any
135 * @returns {boolean}
136 */
137export declare function isPromiseBasedObservable(value: any): value is IPromiseBasedObservable<any>;
138export {};