Following is a store using Valtio, That thing works as expected but need way to type-hint this. The goal is to create store that will hold an object & allows to update any value/ values by using action method, while not requiring to define action methods for every use case.
I have a problem with the type check in the below code:
import { proxy } from 'valtio';
type PaymentStore = {
loading: boolean;
token: string | null;
id: string | null;
initialized: boolean;
total: number;
processing: boolean;
paid: boolean;
isError: boolean;
errMsg: null | string;
};
const defaultValues: PaymentStore = {
loading: false,
token: null,
id: null,
initialized: false,
total: 0,
processing: false,
paid: false,
isError: false,
errMsg: null,
};
const paymentStore = proxy<PaymentStore>(defaultValues);
const paymentActions = {
setProperty<T extends keyof PaymentStore>(key: T, value: PaymentStore[T]) {
paymentStore[key] = value
},
setProperties<T extends Partial<{[k in keyof PaymentStore]: PaymentStore[k]}>>(values: T) {
Object.keys(values).forEach((valueKey) => {
// @ts-ignore
paymentStore[valueKey] = values[valueKey]; // >>> how to type this line?
})
}
}
// getting excellent aut-complete in following methods
paymentActions.setProperty('loading', false);
paymentActions.setProperties({
loading: true,
isError: true,
});
You have 2 problems with the above line of code:
paymentStore[valueKey]is a dynamic value, so we don't know the type of that field beforehand withPaymentStoreonly. You have to assignpaymentStorevariable withRecord<keyof PaymentStore, unknown>.unknownin this context is to tell the type check that you don't know the type for now but you know the key is a part ofPaymentStoretypedKeyinvalues[typedKey]is a string because offorEachparams. Therefore, you can not matchkeyof PaymentStorewithstring. You have to assert that type withas keyof PaymentStoreYou can try the below approach with some comments in the code
Playground link