How to make setStore treat a class/interface as an opaque value instead of a partiable one?

So, I'm currently using a UOM library called @buge/ts-units. It has this interface called Quantity that I want to use in my stores. For example:
type Rectangle = {
// Length is an instance of Quanity
// Length = Quantity<...>
width: Length
height: Length
}
type Rectangle = {
// Length is an instance of Quanity
// Length = Quantity<...>
width: Length
height: Length
}
The problem is that whenever I want to use setStore with the path syntax, this is allowed:
// No errors:
setRectangleStore("width", 0)

// function inches(length: number): Length
// It should only allow:
setRectangleStore("width", inches(0))
// No errors:
setRectangleStore("width", 0)

// function inches(length: number): Length
// It should only allow:
setRectangleStore("width", inches(0))
It seems to be because in Typescript, the type used for the last argument is Partial<Length>, which allows a number(???) to be accepted. Ignoring that, I would want to treat Length as a opaque, unpatchable, immutable value just like any other primitive type (boolean, number, bigint, et cetera). The work around I found is essentially avoiding the path syntax and merge at the top-level:
// Good
setRectangleStore({ width: inches(0) })

// Errors as expected:
setRectangleStore({ width: 0 })
// Good
setRectangleStore({ width: inches(0) })

// Errors as expected:
setRectangleStore({ width: 0 })
1 Reply
utrain
utrainOP3w ago
Okay, I decided to try patching it myself and pulled from SolidStore.Unwrappables. It's supposed to include anything that shouldn't be wrapped reactively. Though, it doesn't imply the object in question shouldn't be patchable, it works okay-enough for my purposes. I changed the type of StoreSetter, which determines how some value should be modified, to be this instead:
type TryCustomPartializing<T> = T extends Unwrappable ? T : CustomPartial<T>
export type StoreSetter<T, U extends PropertyKey[] = []> = TryCustomPartializing<T> | ((prevState: T, traversed: U) => TryCustomPartializing<T>)
type TryCustomPartializing<T> = T extends Unwrappable ? T : CustomPartial<T>
export type StoreSetter<T, U extends PropertyKey[] = []> = TryCustomPartializing<T> | ((prevState: T, traversed: U) => TryCustomPartializing<T>)
So, now the partialization is behind a condition. And it solves my problem, I guess? Is there a better way?
Want results from more Discord servers?
Add your server