Skip to content

Commit

Permalink
Fix flow typings [requires TS3.6] (#2160)
Browse files Browse the repository at this point in the history
* fix for flow typings

* undo changelog formatting

* put proper set type

* fix async generator typing in flows
  • Loading branch information
xaviergonz authored and mweststrate committed Nov 7, 2019
1 parent 4d56bf6 commit 728ad70
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 46 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
- cancelled flows now reject with a `FlowCancellationError` instance whose error message is the same as in previous versions (`"FLOW_CANCELLED"`) so this is not breaking.
- Fixed flow typings with Typescript v3.6. This means that version of Typescript is required when using flows.
- Cancelled flows now reject with a `FlowCancellationError` instance whose error message is the same as in previous versions (`"FLOW_CANCELLED"`) so this is not breaking.
- Fix running mobx in web worker [#2184](https://github.com/mobxjs/mobx/pull/2184/files)
- Fixed flow typings for Facebook's Flow. A new `CancellablePromise` Flow type is exported.

Expand Down
41 changes: 7 additions & 34 deletions src/api/flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,9 @@ export function isFlowCancellationError(error: Error) {

export type CancellablePromise<T> = Promise<T> & { cancel(): void }

export interface FlowYield {
// fake, only for typing
"!!flowYield": undefined
}

export interface FlowReturn<T> {
// fake, only for typing
"!!flowReturn": T
}

// we skip promises that are the result of yielding promises (except if they use flowReturn)
export type FlowReturnType<R> = IfAllAreFlowYieldThenVoid<
R extends FlowReturn<infer FR>
? FR extends Promise<infer FRP>
? FRP
: FR
: R extends Promise<any>
? FlowYield
: R
>

// we extract yielded promises from the return type
export type IfAllAreFlowYieldThenVoid<R> = Exclude<R, FlowYield> extends never
? void
: Exclude<R, FlowYield>

export function flow<R, Args extends any[]>(
generator: (...args: Args) => IterableIterator<R>
): (...args: Args) => CancellablePromise<FlowReturnType<R>> {
generator: (...args: Args) => Generator<any, R, any> | AsyncGenerator<any, R, any>
): (...args: Args) => CancellablePromise<R> {
if (arguments.length !== 1)
fail(!!process.env.NODE_ENV && `Flow expects 1 argument and cannot be used as decorator`)
const name = generator.name || "<unnamed flow>"
Expand All @@ -52,10 +26,9 @@ export function flow<R, Args extends any[]>(
const ctx = this
const args = arguments
const runId = ++generatorId
const gen = action(`${name} - runid: ${runId} - init`, generator).apply(
ctx,
(args as any) as Args
)
const gen = action(`${name} - runid: ${runId} - init`, generator as (
...args: Args
) => Generator<any, R, any>).apply(ctx, (args as any) as Args)
let rejector: (error: any) => void
let pendingPromise: CancellablePromise<any> | undefined = undefined

Expand Down Expand Up @@ -110,7 +83,7 @@ export function flow<R, Args extends any[]>(
try {
if (pendingPromise) cancelPromise(pendingPromise)
// Finally block can return (or yield) stuff..
const res = gen.return!()
const res = gen.return!(undefined as any)
// eat anything that promise would do, it's cancelled!
const yieldedPromise = Promise.resolve(res.value)
yieldedPromise.then(noop, noop)
Expand All @@ -121,7 +94,7 @@ export function flow<R, Args extends any[]>(
rejector(e) // there could be a throwing finally block
}
})
return promise as CancellablePromise<FlowReturnType<R>>
return promise as CancellablePromise<R>
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/computedvalue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
newObserving = null // during tracking it's an array with new observed observers
isBeingObserved = false
isPendingUnobservation: boolean = false
observers = new Set()
observers = new Set<IDerivation>()
diffValue = 0
runId = 0
lastAccessedBy = 0
Expand Down
20 changes: 16 additions & 4 deletions test/base/typescript-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1557,9 +1557,9 @@ test("it should support asyncAction as decorator (ts)", async () => {
class X {
@observable a = 1

f = mobx.flow(function* f(initial: number): any {
f = mobx.flow(function* f(this: X, initial: number) {
this.a = initial // this runs in action
this.a += yield Promise.resolve(5)
this.a += yield Promise.resolve(5) as any
this.a = this.a * 2
return this.a
})
Expand Down Expand Up @@ -1590,7 +1590,7 @@ test("flow support async generators", async () => {
total += number
}
return total
} as any) // TODO: fix typings
})

const p = start()
const res = await p
Expand All @@ -1615,7 +1615,7 @@ test("flow support throwing async generators", async () => {
total += number
}
return total
} as any) // TODO: fix typings
})

const p = start()
try {
Expand Down Expand Up @@ -1648,6 +1648,18 @@ test("verify #1528", () => {
expect(appState.timer).toBe(0)
})

test("type of flows that return promises", async () => {
mobx.configure({ enforceActions: "observed" })

const f = mobx.flow(function* f() {
return Promise.resolve(5)
})

const n: number = await f()
expect(n).toBe(5)

})

test("#2159 - computed property keys", () => {
const testSymbol = Symbol("test symbol")
const testString = "testString"
Expand Down
12 changes: 6 additions & 6 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8114,9 +8114,9 @@ ts-jest@^24.0.0:
yargs-parser "10.x"

tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
version "1.9.3"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==
version "1.10.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==

tsutils@^3.7.0:
version "3.10.0"
Expand Down Expand Up @@ -8173,9 +8173,9 @@ typedarray@^0.0.6:
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=

typescript@^3.3.3333:
version "3.4.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.4.tgz#aac4a08abecab8091a75f10842ffa0631818f785"
integrity sha512-xt5RsIRCEaf6+j9AyOBgvVuAec0i92rgCaS3S+UVf5Z/vF2Hvtsw08wtUTJqp4djwznoAgjSxeCcU4r+CcDBJA==
version "3.6.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.4.tgz#b18752bb3792bc1a0281335f7f6ebf1bbfc5b91d"
integrity sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==

uglify-js@^3.1.4:
version "3.5.5"
Expand Down

0 comments on commit 728ad70

Please sign in to comment.