Skip to content
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

Add toGenerator utility function #1543

Merged
merged 5 commits into from
Jul 11, 2020

Conversation

fruitraccoon
Copy link
Contributor

The toGenerator function is intended for wrapping a promise-returning function to create a generator-returning function. This can then be used to obtain a strongly-typed return value in async actions using yield* (rather than yield).

This approach has been discussed in this Spectrum thread.

@fruitraccoon
Copy link
Contributor Author

Please note that I've not regenerated the docs (which causes a single test failure), as when I do there are many changes relating to the name of my fork project, rather than the real one.

The toGenerator function is intended for wrapping a promise-returning function
to create a generator-returning function. This can then be used to obtain a
strongly-typed return value in async actions using `yield*`.
@Bnaya
Copy link
Member

Bnaya commented Jul 1, 2020

Thanks @fruitraccoon! i will review it at the weekend i believe

@Bnaya Bnaya self-requested a review July 1, 2020 12:22
Copy link
Member

@Bnaya Bnaya left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will figure out now what we should do with the docs

packages/mobx-state-tree/src/utils.ts Outdated Show resolved Hide resolved
packages/mobx-state-tree/src/utils.ts Outdated Show resolved Hide resolved
const m = M.create()

const result = await m.testAction()
ensureNotAny(result)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that the repo is upgraded to ts 3.9, we may use
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-9.html#-ts-expect-error-comments
for this kind of assertions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I can use @ts-expect-error in this case? If I understand correctly, it's for when typescript wants to report an error, but in the context of the test it's the intended code.

In this test I'm wanting the opposite, as what I'm testing for is that the type of the returned value is "not any", which never normally shows up as an error of course. With the current code, if I change one of the yield* calls to just be yield, a typescript error appears (as intended).

I've simplified the check from two functions to one, and added a comment. Let me know if I've misunderstood though!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What you cloud do:

// result return type is string. if there is no type error here, means we have wrong return type
// @ts-expect-error
const notAny: number =  result
;
const isString: string =  result;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't think of that approach - nice!

I couldn't think of a way to have a "one-liner" to do both checks though (a la the ensureNotAnyType function). Would you prefer to keep the tests as they are now, or switch them to the technique above?

@Bnaya
Copy link
Member

Bnaya commented Jul 4, 2020

Would you mind adding also:

/**
 * @experimental 
 * experimental api - might change on minor/patch releases
 * 
 * Convert a promise to a generator yielding that promise
 * This is intended to allow for usage of `yield*` in async actions to
 * retain the promise return type.
 *
 * Example:
 * ```ts
 * function getDataAsync(input: string): Promise<number> { ... }
 *
 * const someModel.actions(self => ({
 *   someAction: flow(function*() {
 *     // value is typed as number
 *     const value = yield* promiseToGenerator(getDataAsync("input value"));
 *     ...
 *   })
 * }))
 * ```
 */
function* promiseToGenerator<R>(p: Promise<R>): Generator<Promise<R>, R, R> {
  return yield p as any;
}

And a test
It's really ok it won't happen on this PR:)

The new name is more accurate, based on the description of generators from MDN:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator

> The Generator object is returned by a generator function
Use a single function that ensures the type passed is of the expected type, and
is NOT the typescript `any` type.
@fruitraccoon
Copy link
Contributor Author

No problem, I've added the extra function to convert a promise. However I've renamed both it and the original function, as when I look at MDN for generators:

The Generator object is returned by a generator function ...

So my original function name choice was not ideal. So now the original function is called toGeneratorFunction and the new one that converts a promise to a generator is called toGenerator.

But let me know if you prefer the original names, something shorter, or something different altogether.

@Bnaya
Copy link
Member

Bnaya commented Jul 9, 2020

No problem, I've added the extra function to convert a promise. However I've renamed both it and the original function, as when I look at MDN for generators:

The Generator object is returned by a generator function ...

So my original function name choice was not ideal. So now the original function is called toGeneratorFunction and the new one that converts a promise to a generator is called toGenerator.

But let me know if you prefer the original names, something shorter, or something different altogether.

I personally prefer verbose names (promiseToGenerator)
And one of the reason we mark these functions as experimental is so we can rename them later with out breaking change if w find the name not good.

So i think we can take out the PR from draft mode?

@fruitraccoon fruitraccoon marked this pull request as ready for review July 9, 2020 23:21
@Bnaya Bnaya merged commit 126ab41 into mobxjs:master Jul 11, 2020
@Bnaya
Copy link
Member

Bnaya commented Jul 11, 2020

Merged! thank you!

@Bnaya
Copy link
Member

Bnaya commented Jul 11, 2020

Released as v3.17.1, I'm trying to figure out how to update the website
The docs in the repo are updated:
https://github.com/mobxjs/mobx-state-tree/blob/10808b91a96a537b69d77904b2657d7a2b04ffb7/docs/API/index.md#togenerator

Bnaya added a commit that referenced this pull request Jul 11, 2020
Bnaya added a commit that referenced this pull request Jul 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants