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

Rethink how overloads are handled #743

Open
Rich-Harris opened this issue Oct 31, 2024 · 2 comments
Open

Rethink how overloads are handled #743

Rich-Harris opened this issue Oct 31, 2024 · 2 comments

Comments

@Rich-Harris
Copy link
Member

At the moment, when a function has overloads, we only render the first description — see for example svelte/events#on, where we display this...

Attaches an event handler to the window and returns a function that removes the handler. Using this rather than addEventListener will preserve the correct order relative to handlers added declaratively (with attributes like onclick), which use event delegation for performance reasons

...and disregard all the subtly different ones. The result is that the documentation is incorrect unless you're attaching listeners to window.

Another example is svelte/store#derived, where instead of this (which is gibberish in any case!)...

image

...it might be nice to have something like this, which although a bit repetitive is arguably more comprehensible than what we have now:


derived

This function has four overloads.

  1. Create a Readable store whose value is derived from another store and a fn, which is called when it is first subscribed to and whenever the value of store changes thereafter as long as it has subscribers.

    const count = writable(0);
    const doubled = derived(count, ($count) => $count * 2);
    function derived<S, T>(
      store: Readable<S>,
      fn: (value: S) => T
    ): Readable<T>;
  2. Create a Readable store whose value is derived from multiple stores and a fn, which is called when it is first subscribed to and whenever any of the store values change thereafter as long as it has subscribers.

    const a = writable(1);
    const b = writable(2);
    const sum = derived([a, b], ($a, $b) => $a + $b);
    function derived<Stores extends Readable<any>[], T>(
      stores: Stores,
      fn: (values: Values<Stores>) => T
    ): Readable<T>;
  3. Create a Readable store whose value is updated by calls to set and update arguments provided to fn, which is called when it is first subscribed to and whenever the value of store changes thereafter as long as it has subscribers.

    If fn returns a function, it will be called before fn re-runs, and when there are no more subscribers, allowing you to perform cleanup work.

    An optional third argument provides an initial value, if set/update are called asynchronously.

    const count = writable(0);
    const delayed = derived(count, ($count, set) => {
      const timeout = setTimeout(() => {
        set($count);
      }, 1000);
    }, 0);
    function derived<S, T>(
      store: Readable<S>,
      fn: (
        value: S,
        set: (value: T) => void,
        update: (fn: Updater<T>) => void
      ) => Unsubscriber | void,
      initial?: T | undefined
    ): Readable<T>;
  4. Create a Readable store whose value is updated by calls to set and update arguments provided to fn, which is called when it is first subscribed to and whenever the value of stores change thereafter as long as it has subscribers.

    If fn returns a function, it will be called before fn re-runs, and when there are no more subscribers, allowing you to perform cleanup work.

    An optional third argument provides an initial value, if set/update are called asynchronously.

    const a = writable(1);
    const b = writable(2);
    const delayed = derived([a, b], ([$a, $b], set) => {
      const timeout = setTimeout(() => {
        set($a + $b);
      }, 1000);
    }, 0);
    function derived<Stores extends Readable<any>[], T>(
      stores: Readable<S>,
      fn: (
        value: Values<Stores>,
        set: (value: T) => void,
        update: (fn: Updater<T>) => void
      ) => Unsubscriber | void,
      initial?: T | undefined
    ): Readable<T>;

Perhaps more importantly, having separate overloads like this would mean more appropriate inline documentation (though TS will default to the first overload, in cases where inference isn't yet possible).

Above all, this has reminded me how much I hate overloads.

@linear linear bot added the svelte.dev label Nov 5, 2024
@Ocean-OS
Copy link
Contributor

Perhaps to help newer devs understand, we could use another term instead of "overloads"?
I'm not exactly sure what the replacement would be, but overloads isn't a term most new devs know.

@Rich-Harris
Copy link
Member Author

Also: sveltejs/svelte#14800

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

No branches or pull requests

2 participants