-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
[Types] Strictly typed store allows invalid values #95
Comments
I don’t understand why TypeScript does this. You can experiment with the behavior here. Here's a workaround: const [useStore] = create<Store>((set): Store => ({ // additional type declaration
count: 0,
invalidA: 0, // errors
increase: () => set(state => ({ count: state.count + 1 }))
})); |
I assume that this is due to the structural/duck typing - any superset of Store is assignable to Store because it has all properties of Store? |
You're right. I learned it has to do with structural typing. Excess properties are allowed with structural typing. TypeScript does have excess property checking but it's only when explicitly defining an object of a specific type. Here is a good article about it: |
I think this is resolved. |
I got some typescript issue. Zustand can't infer the type of State from my creator. Example: https://codesandbox.io/s/test-zustand-74jze?file=/src/App.tsx export function createItem(name: string) {
const api = create((set) => {
return {
name,
count: 1,
setName: (newName: string) => {
// set((prev) => {
// // prev
// });
}
};
});
console.log(api.getState().invalid); // expect this line to trigger ts error, but it doesn't
} |
@csr632 Yeah, I noticed that too and it's annoying for me personally. If you remove export function createItem(name: string) {
const api = create(() => {
return {
name,
count: 1,
setName: (newName: string) => {
// set((prev) => {
// // prev
// });
}
};
}); Only solution I have now is to manually type state: https://codesandbox.io/s/test-zustand-forked-mo5rs |
Maybe related to this ts design limitation: microsoft/TypeScript#25092 (comment) Could we re-design zustand's API so that it doesn't encourage user to write "context-sensitive function"?
|
I'm not sure if I understand the term context-sensitive function. |
As microsoft/TypeScript#25092 (comment) said:
In this case: const api = create((set) => { // this is a context-sensitive because it has untyped function parameters ”set“
return {
name,
count: 1,
};
}); So
Yes, we should never use the params: const api = create(() => { // this is NOT a context-sensitive function because it doesn't list any params
// we should never use the params
return {
name,
count: 1,
setName: (newName: string) => {
// we use `api.set` instead of the `set` from param
api.setState((prev) => ({
count: prev.count + 1
}));
}
};
}); Checkout codesandbox. But I think this is somehow ugly... |
Thanks. I got it. That's what I noted recursive type definition. Now I learned the proper term: context sensitive. Thanks for your example. import create from "zustand";
const useStore = create(() => {
const set = (...args: Parameters<typeof useStore.setState>) =>
useStore.setState(...args);
return {
name: "",
count: 1,
setName: (newName: string) => {
set((prev) => ({
name: newName
}));
}
};
}); This pattern doesn't allow us to add middleware. So, I'm not sure if we recommend it as a first class usage. |
They are basically technical limitations, but could we somehow mitigate them? |
I might be missing something, but shouldn't following disallow
invalidA
andinvalidB
values to be used in a store? As it is at the moment I don't get any error about them.The text was updated successfully, but these errors were encountered: