solidjs / solid

A declarative, efficient, and flexible JavaScript library for building user interfaces.
https://solidjs.com
MIT License
32.4k stars 922 forks source link

Store values don't work with "in" operator check #1331

Closed illiaChaban closed 1 year ago

illiaChaban commented 2 years ago

Describe the bug

Store doesn't respect "in" operator check

I have an app that does optimistic updates, meaning I update UI first -> make request to api and get extra data like "createdAt" value -> update store with api values

Derived signal "addingItems" calculates items that are being currently added by using filter(item => !('createdAt' in item && item.createdAt)) check. This does not work.

Looks like store doesn't respect "'createdAt' in item && item.createdAt" expression as property access. Now if i update my expression to item => !item.createdAt it works fine, but working with typescript I want to be very explicit and it doesn't allow for property access if the type is something like {value: any} | {value:any; createdAt: string}

Your Example Website or App

https://playground.solidjs.com/?hash=642146625&version=1.4.1

Steps to Reproduce the Bug or Issue

  1. Go to provided link
  2. Click "add item" button
  3. "Number of items pending api call" should update to 0 after 200ms of adding a new item after store update, but it does not

Expected behavior

"Number of items pending api call" should update to 0 after 200ms of adding a new item

Screenshots or Videos

No response

Platform

Additional context

No response

Brendan-csel commented 2 years ago

Interesting I was able to create simple reproduction in vs 1.4.1 but it seems to be resolved in 1.6.1...

https://playground.solidjs.com/?hash=-1044794998&version=1.4.1

https://playground.solidjs.com/?hash=1081256110&version=1.6.1

EDIT: Still doesn't work with your example inside the array filter predicate though.

deluksic commented 2 years ago

Seems like filter predicate works in this case at least:

https://playground.solidjs.com/?hash=1228092278&version=1.6.1

NVM this is when the field is deleted, not added.

deluksic commented 2 years ago

Regarding typescript, this is what you could do:

type KeysOfUnion<T> = T extends T ? keyof T: never;
function hasField<T extends Record<string, unknown>, K extends KeysOfUnion<T>>(value: T, field: K) {
  return value[field] !== undefined && field in value;
}

And then use it:

value.items.filter(i => !hasField(i, 'createdAt'))

https://playground.solidjs.com/?hash=-1325227638&version=1.4.1

mdynnl commented 2 years ago

I think we need to track self to support ts in operator narrowing (not that much of a problem for me though), currently you kinda have to workaround like above comment.

Don't take this as an official way to do this as it's not currently documented, but you can do i._ which is basically the same as i[$TRACK], so 'prop' in ((i as any)[$TRACK], i) && i.prop and typescript will be happy narrowing.

Also, https://playground.solidjs.com/?hash=1081256110&version=1.6.1 works because prop access is there. This is probably a bug and we need to either track self or create a node on in operator.