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

Fix mutateCallback types #745

Merged
merged 5 commits into from
Nov 13, 2020
Merged

Fix mutateCallback types #745

merged 5 commits into from
Nov 13, 2020

Conversation

avocadowastaken
Copy link
Contributor

@avocadowastaken avocadowastaken commented Nov 4, 2020

1. Promise<Data | undefined> because mutate implementation handles undefined values.

mutate implementation can pass undefined values to the mutateCallback:

swr/src/use-swr.ts

Lines 138 to 144 in 9e734aa

if (_data && typeof _data === 'function') {
// `_data` is a function, call it passing current cache value
try {
data = await _data(cache.get(key))
} catch (err) {
error = err
}

@shuding
Copy link
Member

shuding commented Nov 5, 2020

Actually mutate doesn't accept undefined as the data. The implementation is for specific cases like mutate(key) (no data specified, only revalidate).

Generally we don't want you to do this:

mutate(key, () => undefined)

Because in SWR undefined is like a special placeholder which means "no data available", so you can't set undefined as the data.

@avocadowastaken
Copy link
Contributor Author

Actually mutate doesn't accept undefined as the data. The implementation is for specific cases like mutate(key) (no data specified, only revalidate).

Generally we don't want you to do this:

mutate(key, () => undefined)

Because in SWR undefined is like a special placeholder which means "no data available", so you can't set undefined as the data.

Thanks for clearing things out.


The main problem that we've faced is that sometimes when we're calling mutate with callback and currentValue comes as undefined, so mutateCallback should look like that:

export type mutateCallback<Data = any> = (
-  currentValue: Data
+  currentValue: undefined | Data
) => Promise<Data> | Data

But this leads to another problem when we have only part of the value to update:

function updateStatus(guid: string, status: string): void {
  mutate(`/user/${guid}`, (user) => ({ ...user, status }));
}

It will create { status: string } object when we do not have currentValue, so we want to check if currentValue is undefined

function updateStatus(guid: string, status: string): void {
  mutate(`/user/${guid}`, (user) => !user ? user : ({ ...user, status }));
}

Here TS will fail because it expects the result of the mutateCallback to be Promise<Data> | Data, so we have to change mutateCallback types to:

  export type mutateCallback<Data = any> = (
-  currentValue: Data
- ) => Promise<Data> | Data
+  currentValue: undefined | Data
+ ) => Promise<Data | undefined> | Data | undefined

@avocadowastaken avocadowastaken changed the title Fix mutateInterface types Fix mutateCallback types Nov 5, 2020
@avocadowastaken
Copy link
Contributor Author

@shuding hey, sorry to disturb, but can you check one more time please, and if it can't be merged I'll just close this PR.

@shuding
Copy link
Member

shuding commented Nov 13, 2020

@umidbekkarimov Sorry for the delay!

Now I understand your use case and I think that makes sense. We can have it. 👍
The only request is can we add a test case for it, since it's a new behavior? It's fine if you are busy and we can take this PR and open an issue (for the test case) for now.

Thanks for the contribution!

@avocadowastaken
Copy link
Contributor Author

avocadowastaken commented Nov 13, 2020

@umidbekkarimov Sorry for the delay!

Now I understand your use case and I think that makes sense. We can have it. 👍
The only request is can we add a test case for it, since it's a new behavior? It's fine if you are busy and we can take this PR and open an issue (for the test case) for now.

Thanks for the contribution!

Done. I could not add checks in TS because #741 was merged to next, but I add repro in the ts playground: https://www.typescriptlang.org/play?#code/KYDwDg9gTgLgBDAnmYcC2BXGBDGwDC2ANkQEbYDGA1gDwAiu2cAvHNgHaIB8LcAFACg4cChihRg7GADViGYAC44GdgBNgAMwCW7YKrgAfOAxwCAlCx4AFKBDRaAzsBor123fqMnsPI6806eobGjAKgkLAIyKgSDpDsTgCSUsBQGpTO3gA0cACi4tA8rADeQnCqjAD8St5lqbZQ1XkFUGUSAG7EWhV4SnwWzNa29k40pBAQRMAcXGWYOL38ZcI92E3ewTZ2jpmMvuhYuATEZJS03lxZy3AOABYQGESqAErAnUTdR03jk9PsZQMhttRhs-GoAh5ZsJHLIPj0dABzJQ-KYcAQAXwEAgA9Ni4AABGAOAC04WAFBgpJaAgoEAS8Fi8ScSkZdKSKTSGRo7AwaFIqRy+QaRTgxUxAlZCWAADp5kc+HxROJJDI5MBAaKykqJFJYfJpTAIAAxLQgIK4uDpLREBxlLHCC0AQQoFGAYCJynB7j0ZS0Gn4AEJtSq9erNcJhBIYGJ2J63IFVABuMriyPAaNQWPB3Vq5PosxAA

Copy link
Member

@shuding shuding left a comment

Choose a reason for hiding this comment

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

Thanks! This is already looking great. When we move to next strict mode will work 👍

@shuding shuding merged commit 26f569b into vercel:master Nov 13, 2020
@Zertz
Copy link

Zertz commented Nov 18, 2020

First, thanks for improving the types, this will definitely help make apps more robust!

I'm not sure where to ask this and I understand swr is 0.x but are type breaks like this considered a breaking change or more like a bug?

@avocadowastaken avocadowastaken deleted the mutate-nullable branch November 18, 2020 14:14
@shuding
Copy link
Member

shuding commented Nov 18, 2020

@Zertz This PR is a bug fix and should be available in the latest release already (if not please let me know).

But regarding TS strict mode, I'd consider it a pretty breaking change because we need to revamped the core code base and the tests. The goal is to also have better type names in the 1.0 version.

shuding added a commit that referenced this pull request Dec 16, 2020
* 0.3.8

* replace rIC with rAF (#744)

* Fix race condition when calling mutate synchronously (#735)

* fix race condition when calling mutate synchronously

* fix test

* add comment

* fix code reviews

* refactor: support SSR in Deno (#754)

* refactor: support SSR in Deno

* refactor: improve Deno determining

* Add @ts-ignore

Co-authored-by: Shu Ding <g@shud.in>

Co-authored-by: Shu Ding <g@shud.in>

* fix eslint error (#768)

* Fix `mutateCallback` types (#745)

* Fix `mutateCallback` types

* WIP

* Add CodeSandbox CI (#769)

* add CodeSandbox CI

* add new line

* fix install cmd

Co-authored-by: Paco <34928425+pacocoursey@users.noreply.github.com>

* dispatch's payload type is actionType and run lint (#772)

* chore: payload is actionType

* chore: move a ts-ignore comment

* Fix suspense (#777)

* fix #494

* add comment

* rename to initialMountedRef

* 0.3.9

* fix: mark isValidating as false when key is falsy (#757)

* fix: tear down when key turns to empty

* use false for empty key

* Fix README.md typo (#783)

'/api/data' => '/api/user' in "Multiple Arguments"

* fix: do mount check in config callback (#787)

* Update api-hooks example README.md (#790)

Updated the Vercel deploy link to the correct directory

* Return '@null' if args is null ASAP (#767)

* chore: return 'null' if arg[i] is null ASAP

* chore: update comment

* chore: use continue

* Bump ini from 1.3.5 to 1.3.8 (#806)

Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.8.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](npm/ini@v1.3.5...v1.3.8)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* update test

Co-authored-by: Shu Ding <g@shud.in>
Co-authored-by: X <git@iamje.com>
Co-authored-by: Umidbek Karimov <uma.karimov@gmail.com>
Co-authored-by: Paco <34928425+pacocoursey@users.noreply.github.com>
Co-authored-by: matamatanot <39780486+matamatanot@users.noreply.github.com>
Co-authored-by: Jiachi Liu <inbox@huozhi.im>
Co-authored-by: sAy <47605337+mingcenwei@users.noreply.github.com>
Co-authored-by: William Crutchfield <william.r.crutchfield@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
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.

3 participants