I am attempting to make a TypeScript interface that will allow for a given data structure to be compatible with useSyncExternalStore. This is to follow to reduce the load on larger Zustand stores in the application.
This is a modification of the code found at: https://react.dev/reference/react/useSyncExternalStore
First, I make a Subscribable
interface that is implemented on the TodoStore
class.
The code below can be found at: https://codesandbox.io/s/usesyncexternalstore-test-dxgg5k?file=/src/App.tsx
export interface Subscribable {
subscribe(listener: Function): Function;
getSnapshot(): any;
emitChange(): void;
}
export class TodosStore {
todos: any[] = [];
nextId: number = 0;
listeners: Function[] = [];
addTodo() {
this.todos = [
...this.todos,
{ id: this.nextId++, text: "Todo #" + this.nextId }
];
this.emitChange();
}
subscribe(listener: Function): Function {
this.listeners = [...this.listeners, listener];
return () => {
this.listeners = this.listeners.filter((l) => l !== listener);
};
}
getSnapshot(): any[] {
return this.todos;
}
emitChange() {
for (let listener of this.listeners) {
listener();
}
}
}
Then on App.tsx
, I create a new instance of this store and subscribe to it.
import { useSyncExternalStore } from "react";
import { TodosStore } from "./todoStore";
let list = new TodosStore();
export default function App() {
const subscribedList = useSyncExternalStore(list.subscribe, list.getSnapshot); // Error here
return (
<>
<button onClick={() => list.addTodo()}>Add todo</button>
<hr />
<ul>
{subscribedList.map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
</>
);
}
useSyncExternalStore throws a type error for my subscribe method
Argument of type '(listener: Function) => Function' is not assignable to parameter of type '(onStoreChange: () => void) => () => void'.
Type 'Function' is not assignable to type '() => void'.
Type 'Function' provides no match for the signature '(): void'.ts(2345)
To my understanding, the subscribe method must return an unsubscribe function for the hook. However, setting the return type as Function results in a signature error.
It also throws an error within the getSnapshot method for referencing class variables:
Cannot read properties of undefined (reading 'todos')
Give it a better TS type. Instead of Function
, use () => void
.