swrv icon indicating copy to clipboard operation
swrv copied to clipboard

Possible `key` type mismatch

Open mv-go opened this issue 2 years ago • 11 comments

According to docs something like this should be possible: image

However, the following code triggers a TS type mismatch warning

const maybeUndefined = ref<string>()

const { data, error, mutate } = useSWRV(
  () => maybeUndefined.value && `my unuque key ${maybeUndefined.value}`,
  async () => {
    const r = await axiosInstance.get(`myUrl/${maybeUndefined.value}`)
    return r
  },
)

Warning reads:

Argument of type '() => string | undefined' is not assignable to parameter of type 'IKey'.
  Type '() => string | undefined' is not assignable to type 'keyFunction'.ts(2345)

Upon further digging the issue seems to be in type declaration for keyFunction

export declare type keyType = string | any[] | null;
declare type keyFunction = () => keyType;
export declare type IKey = keyFunction | keyType;

It would seem that amending keyType to

export declare type keyType = string | any[] | null | undefined;

would fix the issue.

However I'm not sure if this doesn't break something down the line :)

mv-go avatar Oct 12 '22 20:10 mv-go

ATM I'm working around this by explicitly returning null in the keyFunction where necessary, however it'd be great to be able to return null || undefined as documentation states

mv-go avatar Oct 12 '22 20:10 mv-go

I think if you defined your original const differently it would pass the checks:

const maybeUndefined = ref<string>('')

// or as null without even declaring a type
const maybeUndefined = ref(null)

But you're saying you should be able to define an "empty" ref, meaning it should be able to be undefined, which I think makes sense, because these should both eval to a falsy value:

const user = ref()
const { data: projects } = useSWRV(() => user.value && '/api/projects?uid=' + user.value.id, fetch)

const user = ref<string>('')
const { data: projects } = useSWRV(() => user.value && '/api/projects?uid=' + user.value.id, fetch)

adamdehaven avatar Oct 13 '22 12:10 adamdehaven

However I'm not sure if this doesn't break something down the line

I'm more concerned about breaking the interface for IKey which it looks like cannot evaluate to undefined

adamdehaven avatar Oct 13 '22 12:10 adamdehaven

Yes, I agree - this could be a breaking change. Speaking of which, I would consider switching the behaviour from falsy to strictly null || undefined. Consider the following case:

const id = ref<number>() // undefined
const { data } = useSWRV(
  () => id.value && `/posts/${id.value}`,
  fetch
)
id.value = 0 // not undefined, but still falsy

In this case, the fetch would not be triggered, however a post (a user, an object) with an id = 0 is a perfectly valid case.

However, maybe in this case, leaving the developer to explicitly return null might be actually not that bad of an idea :)

mv-go avatar Oct 13 '22 13:10 mv-go

n this case, the fetch would not be triggered, however a post (a user, an object) with an id = 0 is a perfectly valid case.

In JavaScript, 0 is considered a falsy value. Source

adamdehaven avatar Oct 14 '22 13:10 adamdehaven

In JavaScript, 0 is considered a falsy value. Source

I understand, yes. So in my example above you would suggest that fetch should not be triggered when id is changed from undefined to 0?

mv-go avatar Oct 14 '22 13:10 mv-go

So in my example above you would suggest that fetch should not be triggered when id is changed from undefined to 0?

Correct, because they both evaluate as falsy.

adamdehaven avatar Oct 14 '22 14:10 adamdehaven

Is this a desired behaviour?

It would seem common to have an object on the backend with an id = 0

mv-go avatar Oct 14 '22 15:10 mv-go

Instead of thinking about something with an id, think about an iterator.

If I have a starting value of an iterator as let i = 0 and increment in a loop or something when I have data and/or processing something, I'd only want the fetcher to run when the value of i is non-falsy (i.e. not 0).

I see your use-case; however, I would think if you know you're dealing with falsy values coming from your data structure you would use something you know that cannot equate to falsy as your dependent fetcher key.

adamdehaven avatar Oct 14 '22 15:10 adamdehaven

Fair enough. Should we consider implementing changes regarding my initial message in this issue - to include undefined in typings. Or shall we just close this one as irrelevant? :)

mv-go avatar Oct 14 '22 15:10 mv-go

I'm still wondering if adding undefined to keyType invalidates the IKey interface

adamdehaven avatar Oct 14 '22 16:10 adamdehaven