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

Improve type definition of create to accept CustomSetState #428

Closed
wants to merge 14 commits into from

Conversation

hachibeeDI
Copy link

@hachibeeDI hachibeeDI commented Jun 12, 2021

Motivation

I was creating a middleware which returns StateCreator<State, CustomSetState> but it was denied because create is not accept CustomSetState as a second type argument.

Bonus

As you noticed, I modified a test "can set the store without merging" in basic.test.tsx.

Previously StateCreator couldn't infer the state correctly so that store was inferred as object.

// const setState: <never, never, never, never>(partial: PartialState<object, never, never, never, never>, replace?: boolean | undefined) => void
setState({ b: 2 }, true)

// const getState: () => object
getState()

But now it is as it should so we need let TypeScript compiler knows that keys a and b are possibly undefined.

Thanks!

@codesandbox-ci
Copy link

codesandbox-ci bot commented Jun 12, 2021

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 4aa50f1:

Sandbox Source
React Configuration
React Typescript Configuration

@dai-shi
Copy link
Member

dai-shi commented Jun 12, 2021

Hi, thanks for your work! This looks like a good improvement. Does this solve some existing issues?

I haven't looked into details yet, but I think we should keep the JS bundle size. Just added a commit to update the size snapshot. Can you change it to make changes only in TS?

@hachibeeDI
Copy link
Author

Hello! Yes, my issue is going to be solved.
Also, I guess the issue #421 is related to this patch. That error says "Types of parameter 'set' and 'set' are incompatible.

Sure thing! Some of my extra nit pick makes size up. I'll fix it.

@hachibeeDI
Copy link
Author

I confirmed now the JS bundle size is as it was. 👍

Copy link
Member

@dai-shi dai-shi left a comment

Choose a reason for hiding this comment

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

Bundle size is good now. Please check two comments.

typeof partial === 'function'
? (partial as (state: TState) => TState)(state)
: partial
const nextState = typeof partial === 'function' ? partial(state) : partial
Copy link
Member

Choose a reason for hiding this comment

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

Hm, so we can remove the type assertion because of this PR, or was it already possible with the previous one?
Either way, let's remove L71-L72 comments.

Copy link
Author

Choose a reason for hiding this comment

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

Ah, sorry my fix was sloppy it wasn't revert correctly but... it work okay. Sure, gonna remove comments.

src/vanilla.ts Outdated
@@ -109,6 +119,7 @@ export default function create<TState extends State>(

const destroy: Destroy = () => listeners.clear()
const api = { setState, getState, subscribe, destroy }
state = createState(setState, getState, api)
// SetState<TState> includes CustomSetState so it should be ok
Copy link
Member

Choose a reason for hiding this comment

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

Can we do something like this?

diff --git a/src/vanilla.ts b/src/vanilla.ts
index ed33bc2..38d1fd7 100644
--- a/src/vanilla.ts
+++ b/src/vanilla.ts
@@ -62,7 +62,7 @@ export type StateCreator<T extends State, CustomSetState = SetState<T>> = (
 
 export default function create<
   TState extends State,
-  CustomSetState = SetState<TState>
+  CustomSetState extends SetState<TState> = SetState<TState>
 >(createState: StateCreator<TState, CustomSetState>): StoreApi<TState> {
   let state: TState
   const listeners: Set<StateListener<TState>> = new Set()
@@ -119,7 +119,6 @@ export default function create<
 
   const destroy: Destroy = () => listeners.clear()
   const api = { setState, getState, subscribe, destroy }
-  // SetState<TState> includes CustomSetState so it should be ok
-  state = createState(setState as any as CustomSetState, getState, api)
+  state = createState(setState as CustomSetState, getState, api)
   return api
 }

Copy link
Author

Choose a reason for hiding this comment

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

Ahh,I should have figure it out before using any... Thank you for good catch!

Copy link
Author

Choose a reason for hiding this comment

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

Hm, like a test I added, I'd like to apply a CustomSetState that set a different type of state.
In a example, set cannot update readA/B because the second argument is SetState<Pick<ExampleState, 'a' | 'b'>>. However, Pick<ExampleState, 'a' | 'b'> couldn't satisfies TState...

  CustomSetState extends SetState<any> = SetState<TState>

is going to fix setState as any as CustomSetState but test passes. I'll send a patch for your check.

Copy link
Member

@dai-shi dai-shi Jun 13, 2021

Choose a reason for hiding this comment

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

Yeah, that's something I was concerned. Maybe this can't be helped.

SetState includes CustomSetState

I'm not sure if I understand this...

@dai-shi
Copy link
Member

dai-shi commented Jun 19, 2021

Not related, but linking #441.

src/vanilla.ts Outdated
): StoreApi<TState> {
export default function create<
TState extends State,
CustomSetState extends SetState<any> = SetState<TState>
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure what this any would cause. It could cause runtime error without compile error, technically?
@TkDodo can you review this PR please?

@dai-shi
Copy link
Member

dai-shi commented Jun 20, 2021

@hachibeeDI
How is this 9b65883 ?
Does it accomplish what you would like to do?

src/index.ts Outdated Show resolved Hide resolved
src/vanilla.ts Outdated Show resolved Hide resolved
@dai-shi
Copy link
Member

dai-shi commented Jun 21, 2021

Let me hold on this PR. The type improvement seems good, so I'll create a separate PR. (edit: maybe it doesn't mean much.)

@dai-shi
Copy link
Member

dai-shi commented Jul 7, 2021

My big apologies about adding some commits without any success. We should probably start over.
At this point, what we have tried seems to add any in the library code to avoid any in the app code, which doesn't make a lot of sense.
Or, I may misunderstand the original issue. Anyway, let's close this and hope someone to open a new discussion. I'm generally willing to improve types around CustomSetState.

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