Skip to content

Typing question with createSignal() #211

Closed

Description

@hoclun-rigsep

The following code produces this complaint from the compiler: Expected 0 arguments, but got 1. TS2554

const [resetTo$, doResetTo] = createSignal();
doResetTo(5);

whereas this code will compile:

const [resetTo$, doResetTo] = createSignal(x => x);
doResetTo(5);

and so will this:

const [resetTo$, doResetTo] = createSignal<number>();
doResetTo(5);

I'm not sure I find this intuitive, or understand why that overload at

export function createSignal(): [Observable<void>, () => void]
is necessary. Assuming this is all as intended, do you wish me to document it?

Activity

  1. voliva commented on Jun 10, 2021

    @voliva
    Collaborator

    Yep, I see we need to clarify this... maybe we can add a few examples in the API reference for createSignal.

    There are different ways we currently use createSignal:

    • As a void emitter: This is exactly the case you are exposing. createSignal() makes a void Observable - these are for simple events that might happen, e.g. for a button being pressed where you don't care about the event you'd do something like:
    const [buttonPress$, buttonPressed] = createSignal();
    // buttonPress$ is Observable<void>
    // buttonPressed is () => void
    
    // ...
    <button onClick={() => buttonPressed()}>...</button>
    • As a single value: This use case we use it for actions that have a small simple payload in them. But its usage is also quite simple, imagine you mark an item as complete in a list:
    const [itemComplete$, completeItem] = createSignal<number>();
    // itemComplete$ is Observable<number>
    // completeItem is (payload: number) => void
    
    // ...
    
    <button onClick={() => completeItem(id)}>...</button>

    Note that the payload can be any type - it can also be an object or whatever

    • With descriptive arguments: This is when you have actions that have more than one parameter - In this case we use a map function:
    const [statusChange$, setStatus] = createSignal((id: number, status: Status) => ({ id, status }));
    // statusChange$ is Observable<{id: number, status: Status}>
    // setStatus is (id: number, status: Status) => void
    
    // ...
    
    <button onClick={() => setStatus(id, Status.Complete)}>...</button>

    For some of these cases I would use createKeyedSignal though, because it's a bit more descriptive when dealing with keyed instances, but it's hard to come with examples without going into much detail.

  2. hoclun-rigsep commented on Jun 10, 2021

    @hoclun-rigsep
    Author

    Okay. So it looks like users should in general only be putting type parameters on the second case, maybe the first if they really feel like being explicit, and rely on genericity in third case. Good?

  3. voliva commented on Jun 10, 2021

    @voliva
    Collaborator

    Yes... Well, it's just the way that's easier to use IMO.

    • The first case createSignal() is sugar for createSignal(() => {}) - Just faster to type
    • The second case createSignal<number>() is sugar for createSignal((payload: number) => payload) - Again, less characters

    It's not like they should put parameters explicitly, is that if they do, it will be easier to type and read IMO. It was designed like this to make it easier.

  4. locked and limited conversation to collaborators on Jun 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions