interface IAction {
type: string;
payload?: any
}
interface IReducer<T> {
(state: T, action: IAction): T;
}
interface IListenerCallback {
(): void;
}
interface IUnsubscribeCallback {
(): void;
}
class Store<T> {
private _state: T;
private _listeners: IListenerCallback[] = [];
constructor(private reducer: IReducer<T>, initialState: T) {
this._state = initialState
}
getState(): T {
return this._state
}
dispatch(action: IAction): void {
this._state = this.reducer(this._state, action)
this._listeners.forEach((listener: IListenerCallback) => listener())
}
subscribe(listener: IListenerCallback): IUnsubscribeCallback {
this._listeners.push(listener)
return () => {
this._listeners = this._listeners.filter(l => l !== listener)
}
}
}
const reducer: IReducer<number> = (state: number = 0, action: IAction) => {
switch (action.type) {
case "INCREMENT":
return state + 1;
case "DECREMENT":
return state - 1;
default:
return state
}
}
const store = new Store<number>(reducer, 0);
console.log(store.getState())
const unsubscribe = store.subscribe(() => {
console.log("subscribed: ", store.getState());
})
store.dispatch({ type: "INCREMENT" })
store.dispatch({ type: "INCREMENT" })
unsubscribe();
store.dispatch({ type: "DECREMENT" })