Home > other >  What's the difference between Accessor<SomeType> and just SomeType in Typescript?
What's the difference between Accessor<SomeType> and just SomeType in Typescript?

Time:01-10

I'm doing a todo list app in Typescript using Solid. I defined a Todo type as follows:

type Todo = {
  text: string;
  complete: boolean;
};

And later I want to check if all the things to do in the day are done so I can increment my streak. For this I'm using local storage:

const [state, setState] = createStore<{days: number, todos: Todo[]}>({
  days: 0,
  todos: todos,
});

But then TS says something is wrong in the last todos: Type 'Accessor<Todo[]>' is not assignable to type 'Todo[]'.

So, my question is, what's the difference between my Todo[] and this other Accessor<Todo[]>? Where this Accessor comes from? Can/Should I convert it somehow?

CodePudding user response:

In solidJS, Accessor is defined like this:

type Accessor<T> = () => T;

So an Accessor<Todo[]> is a function which returns a Todo[]. As for how to fix this, i'd need to see how the todos variable is created to give specifics, but apparently todos is a function, when instead it needs to be an array. Perhaps you just need to call that function:

const [state, setState] = createStore<{days: number, todos: Todo[]}>({
  days: 0,
  todos: todos(),
});

Or perhaps you need to make a change back where todos is defined.

CodePudding user response:

Accessor is a function that returns the stored value in a signal.

type Accessor<T> = () => T;

Unlike React, Solid do not use virtual DOM and does not re-render upon state update. So it needs function calls to get the value of a signal. That is how Solid achieves reactivity.

The createSignal function returns an array with [Accessor<T>, Setter<T>].

const [item, setItem] = createSignal(10);
        ^
//    This is an Accessor<T>

// To get the stored value, you need to invoke the accessor
console.log(item());

The createStore uses a signal internally and it returns an array with an accessor and a setter. But its accessor uses a proxy object which delegates its property access to the internal signal.

const [todos, setTodos] = createStore([]);
        ^
//    This is a proxied object, not a plain value T

Since only objects and array supports Proxy API, you can only use an object or an array with createStore function.

The exported type signature of the createStore function is not derived but manually typed to suppress complications:

function createStore<T extends object = {}>(...[store, options]: {} extends T ? [store?: T | Store<T>, options?: {
    name?: string;
}] : [store: T | Store<T>, options?: {
    name?: string;
}]): [get: Store<T>, set: SetStoreFunction<T>];

It seems you are trying to store a signal in a store that is how you get that warning but a store value itself is reactive and implements all the necessary API to insert, delete and update items. Avoid storing signals because you would be introducing totally unnecessary abtraction layer.

  • Related