-
Notifications
You must be signed in to change notification settings - Fork 644
[TypeScript 3.6+] flow() | Inferred Generator type is not assignable to IterableIterator #1378
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
With some guidance I'd be interested in this. I believe this is a Mobx issue that MST inherits though? |
Added issue in the mobx repo: mobxjs/mobx#2091 |
I see that the linked mobx issue mentioned above has been closed as the TS typing was deemed not powerful enough. However, I get compile errors when attempting to use TS 3.6.2 with MST flow because of the new types. The code below shows me a typescript error (sorry, I couldn't find anywhere online to create a demo):
The error itself is:
The best workaround that I've found looks like this:
This explicitly types the returned generator. The Perhaps there's a way to update |
Upon further research, new TS typings are indeed not flexible enough to provide strongly typed However, as @fruitraccoon mentioned we now get compile errors, since the new inferred I believe this issue should be about compatibility with TS 3.6+, but I am not quite sure that there's a backward-compatible change to be made, so that's a real problem |
Thanks for looking into it @nulladdict!
I think the second option is obviously better :) |
Sorry for slacking on this. For now I've come up with this temporary solution: import { flow as _flow } from 'mobx-state-tree'
import { FlowReturnType } from 'mobx-state-tree/dist/core/flow'
export type Flow = <T extends Promise<any>, R, Args extends any[]>(
generator: (...args: Args) => Generator<T, R, T extends Promise<infer Y> ? Y : never>
) => (...args: Args) => Promise<FlowReturnType<R>>
export const flow = _flow as Flow Good parts:
Bad part is that whatever TS infers has to be compatible with every single one of the yield calls. flow(function*() {
const x = yield Promise.resolve(42)
const y = yield Promise.resolve('42')
const z = yield Promise.resolve(true)
return null
}) The return type is inferred correctly, but type for Bottom line is, in case of having only one yield call TS works as expected, otherwise we get a union type, which is in my opinion still better than having |
At the moment, when there are multiple yields, I'm falling back to this approach so that it's easier to explicitly type the return variables
Without the I'm keen to hear if anyone has a better approach? |
I would argue, that falling back to Inferred union type is more verbose(you're forced to use "useless" type guard or type A = string | number
const x: A = /* ... */
const y: string = x as string // TS knows it could be done
const z: boolean = x as boolean // TS would complain here In this example Downside is you can still choose an incorrect type from a union, and TS would fail to notice: (playground link) function* f(): Generator<string | number, void, string | number> {
const x = (yield '42') as string // Safe, but ugly and a little awkward
const y = (yield '42') as number // Unsound, ERROR at runtime, but OK in terms of casting
const z = (yield '42') as boolean // Sound, error at compile time
} For my case it is a trade-off I'm willing to take in favour of having |
Of course, I had totally forgotten to try using |
I'd gladly go back to any if it means this will keep working |
you guys should check out As for |
@blacksteed232 thanks, that's actually exactly what I needed. |
@blacksteed232 How do you replace flows where it involves altering the tree? Such as below:
|
actionAsync is an alternative to mobx flows, not mobx state tree ones. To make them work with mobx state tree it would need its own particular implementation (same than there's a different implementation for flows in mobx). That being said I'll cut a new version of mst with the fix for flow typings, but it will make ts 3.6 the new minimum version when using flows |
v3.15.0 released, please give it a try :) How to use it: const M = types
.model({
title: types.string
})
.actions(self => ({
setTitleAsync: flow(function* (newTitle: string) {
yield delay(10)
self.title = newTitle
return 23
}))
})
const m = M.create({})
const n = await m.setTitleAsync("new title") // n is correctly inferred to be a number The only thing that is still not quite working is getting the proper return type from yields, so those will still return any for now and should be type casted. e.g. const whatever: string = yield somethingThatReturnsPromiseString() |
@xaviergonz I'm now able to remove the icky typing and I can confirm it works. Thank you! |
[Typescript] Improving flow typings #1378
Am I correct that For instance: import { types, flow } from 'mobx-state-tree'
const User = types
.model('User', {
id: types.string
})
.actions((self) => ({
getSuggestions: flow(function * () {
const response = yield window.fetch(`http://localhost:3001/suggestions`) // results in any
const suggestions = (yield response.json()) as string[]
self.wishlist.items.push(...suggestions)
})
}))
It's impossible to address that issue as of right now without a forced typecasting, right? |
.json() produces any itself, so I am not sure what else could be inferred
here?
Op wo 20 nov. 2019 11:35 schreef Serj Lavrin <notifications@github.com>:
… Am I correct that yield still results in any type?
For instance:
import { types, flow } from 'mobx-state-tree'
const User = types
.model('User', {
id: types.string
})
.actions((self) => ({
getSuggestions: flow(function * () {
const response = yield window.fetch(`http://localhost:3001/suggestions`) // results in any
const suggestions = (yield response.json()) as string[]
self.wishlist.items.push(...suggestions)
return suggestions
})
}))
response here yield to any.
It's impossible to address that issue as of right now without a forced
typecasting, right?
—
You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub
<#1378?email_source=notifications&email_token=AAN4NBB4Y3IE64TFITDVMJ3QUUOHRA5CNFSM4IQAYWJ2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEERVW7Y#issuecomment-555965311>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAN4NBDIGFP3AYI66JWZA7LQUUOHRANCNFSM4IQAYWJQ>
.
|
It is still somewhat impossible, you can try tricking TS into inferring union type of all yields as described in my comment above, but if you return one of the yielded results from the generator TS freaks out and gives up typing, falling back to edit: and even in union case you still have to use |
It's not about
That's kinda sad. And, if I'm correct, |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs or questions. |
Linked PR released in 3.16.0 |
Feature request
Is your feature request related to a problem? Please describe.
Prior to TS 3.6
flow()
yield return types would be typed asany
due to typescript limitations. Those limitations are being addressed in TS 3.6 release as described in this iteration planDescribe the solution you'd like
Full support for yield return types in
flow()
Describe alternatives you've considered
If the full inference is not possible due to some TS limitations (I haven't completely dived into new generators typings) I wouldn't mind having to manually declare generic parameters in
flow()
Additional context
I've seen some mentions in this PR, but I have not seen the actual issue for tracking this particular case
Are you willing to (attempt) a PR?
The text was updated successfully, but these errors were encountered: