Replies: 4 comments 2 replies
-
Hi @urugator @mweststrate Sorry for bothering you. I'd like to hear your opinion on that. Mobx already have flowResult, why not add one more zero-runtime helper? Even in the documentation example there is an issue: The variable |
Beta Was this translation helpful? Give feedback.
-
@kubk Found my way here too because I can't get the TS version of Flow's to the compile. I've been staring at the example for awhile now. I was keen to utilize the "cancel" method of flows, but its lot looking achievable. |
Beta Was this translation helpful? Give feedback.
-
A bit improved solution with a handy type alias, which I've been using in my projects. export type FlowGenerator<TReturn = void> = Generator<Promise<void>, TReturn, void>;
export function toFlowGeneratorFunction<TArgs extends unknown[], TReturn = void>(
fn: (...args: TArgs) => Promise<TReturn> | TReturn
): (...args: TArgs) => FlowGenerator<TReturn> {
return function* flowGeneratorFunction(...args: TArgs): FlowGenerator<TReturn> {
let value: TReturn = undefined as TReturn;
yield Promise.resolve(fn(...args)).then(result => {
value = result;
});
return value;
};
} I don't know when we could have something like this in Mobx or Mobx-utils, so I have published it as a package |
Beta Was this translation helpful? Give feedback.
-
I'm share my solution, or pattern. I'm using @flow.bound
private async *loadFAQList() {
try {
this.isLoading = true;
const faqList = await this.store.api.faq.fetchAll();
yield;
this.faqList = faqList;
} catch (e) {
yield;
console.error(e);
} finally {
this.isLoading = false;
}
} And some hacks. I can call async mobx flow actions, and await typed result. declare global {
// we can extend built-in AsyncGenerator 👀
// now, all async generators are promises also. No flowResult needs.
interface AsyncGenerator<T = unknown, TReturn = any, TNext = unknown> extends Promise<TReturn> {}
} Then we can do this: class Store {
// return type should be omitted
// return type infer as `AsyncGenerator<never, number[], unknown>` (and `Promise<number[]>` 😁)
@flow.bound async *method() {
return [1,2,3]
}
}
const example = async () => {
const store = new Store();
// return number[] (works!)
const result1 = await store.method()
// explicit type (works!)
const result2: number[] = await store.method()
// @ts-expect-error: Type number[] is not assignable to type string[]
const result3: string[] = await store.method();
} This is not perfect solution, types can still broken, in rare cases. But it works, as long as you follow the pattern. |
Beta Was this translation helpful? Give feedback.
-
Mobx
flow
is great because it allows to write async flows without wrapping observable modifications withaction
/runInAction
. But for TypeScript users it doesn't work well, because TS looses generator types:const a = yield 1; // type 'any' instead of 'number'
There is an open TS issue: microsoft/TypeScript#32523
In MST repo I've found a trick to get type inference working:
or if we want to avoid type casts:
It works with no issue:
But to make it working you should enable
downlevelIteration
in your tsconfig.jsonSo here is my question - should we add this utility function to Mobx codebase too and describe it's usage in documentation? I believe that Mobx
flow
is useless for TS users without this function. Ready to make a PR.We already have
flowResult
function for TS users. So it's better to come up with a better name rather thanresult
:)Beta Was this translation helpful? Give feedback.
All reactions