Skip to content
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

"No overload matches this call" typescript error when passing an array of stores to derived() #6178

Closed
ddanielou opened this issue Apr 9, 2021 · 4 comments · Fixed by #6509
Labels
runtime Changes relating to runtime APIs

Comments

@ddanielou
Copy link

ddanielou commented Apr 9, 2021

Not sure if a typescript or a svelte bug…
I get a "No overload matches this call" typescript error on that kind of code in VSCode:

const stores = [writable(''), writable(0)];
const test1 = derived(stores, () => 'blah'); 

Weirdly, this works

const test2 = derived([writable(''), writable(0)], () => 'blah');

Hovering above the stores constant shows that it's inferred to be an array of Writables, i.e. (Writable<string> | Writable<number>)[], whereas in the test2 example, the array of stores is inferred to be a [Writable<string>, Writable<number>] tuple.

The Stores type declaration in types/runtime/store/index.d.ts (declare type Stores = Readable<any> | [Readable<any>, ...Array<Readable<any>>];) is compatible with the second inference, but not with the first one. Adding | Readable<any>[] to the possible types of Stores seems to fix the issue.

Here's the full typescript error:

No overload matches this call.
  Overload 1 of 2, '(stores: Stores, fn: (values: any, set: (value: unknown) => void) => void | Unsubscriber, initial_value?: unknown): Readable<unknown>', gave the following error.
    Argument of type '(Writable<string> | Writable<number>)[]' is not assignable to parameter of type 'Stores'.
      Type '(Writable<string> | Writable<number>)[]' is not assignable to type '[Readable<any>, ...Readable<any>[]]'.
        Source provides no match for required element at position 0 in target.
  Overload 2 of 2, '(stores: Stores, fn: (values: any) => string): Readable<string>', gave the following error.
    Argument of type '(Writable<string> | Writable<number>)[]' is not assignable to parameter of type 'Stores'.
      Type '(Writable<string> | Writable<number>)[]' is not assignable to type '[Readable<any>, ...Readable<any>[]]'.ts(2769)

Tested on VSCode 1.55 on macOS 11, svelte 3.37, typescript 4.2.4, rollup.

--
Edit: after some more digging, I think it's probably related to microsoft/TypeScript#39244

@stale
Copy link

stale bot commented Jul 8, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale-bot label Jul 8, 2021
@dummdidumm
Copy link
Member

The problem comes down to

const stores = [writable(0), writable(0)];
const test: Stores = stores

The problem is that Stores is typed as "array needs to contain at least one entry", while stores is typed as "array with any length". So the only solution would be to relax the typing, which will result in less TS errors at the cost of possibly more wrong inputs (empty array).

@stale stale bot removed the stale-bot label Jul 8, 2021
@dummdidumm dummdidumm added the runtime Changes relating to runtime APIs label Jul 8, 2021
@ddanielou
Copy link
Author

Hey, thanks for your answer. Now I see the point of using a variadic tuple instead of a typed array – which had me scratching my head.

I toyed with the idea of exporting the Stores interface, which would allow casting:

const stores = [writable(0), writable(0)];
const test = derived(stores as Stores, () => 'test');

… which is already starting to feel dirty. But then other errors kept piling up:

Conversion of type 'Writable<number>[]' to type 'Stores' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
  Type 'Writable<number>[]' is not comparable to type '[Readable<any>, ...Readable<any>[]]'.
    Source provides no match for required element at position 0 in target.

… which I guess could be fixed this way (🤯):

const stores = [writable(0) as Readable<number>, writable(0)];

… which, yeah… let us stop there.

And so, the more it goes, the more I'm thinking that typescript's inference is fundamentally wrong. Any thoughts on this?

dummdidumm added a commit that referenced this issue Jul 9, 2021
With this fix, doing
const stores= [writable(0), writable(1)]
derived(stores, ([a,b,c]) => {});
works without type errors. The propblem with the previous type signature was that it's too strict for TypeScript's suboptimal inference of the value stores in that example, which is Array<Readable<any>>, which does not convey the info "at least one element", which the old Stores signature required.
Runtime-wise, it's no problem passing an empty array to derived.
Fixes #6178
dummdidumm added a commit that referenced this issue Jul 9, 2021
With this fix, doing
```
const stores= [writable(0), writable(1)]
derived(stores, ([a,b,c]) => {});
```
works without type errors. The propblem with the previous type signature was that it's too strict for TypeScript's suboptimal inference of the value `stores` in that example, which is `Array<Readable<any>>`, which does not convey the info "at least one element", which the old Stores signature required.
Runtime-wise, it's no problem passing an empty array to derived.

The new signature is only appended to, not replaced, because the old signature is able to correctly infer the values of each array entry: For `derived([writable(0), writable('foo')], ([a, b]) => {});` the parameters `a` and `b` are correctly inferred as `number` and `string`. If the type would be changed to `type Stores = Readable<any> | Array<Readable<any>>` that would be no longer the case.

Fixes #6178
@Conduitry
Copy link
Member

The types have been loosened in 3.39.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
runtime Changes relating to runtime APIs
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants