Frontend Development 25 min read

Deep Dive into Zustand: Store Creation, TypeScript Types, and Middleware Design

This article explains how Zustand creates stores using the create function, details the TypeScript types such as StateCreator, SetStateInternal, Get and Mutate, demonstrates middleware implementation, clarifies the role of createImpl and useStore, and answers common memory‑leak concerns for React developers.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Deep Dive into Zustand: Store Creation, TypeScript Types, and Middleware Design

Introduction

Zustand is a lightweight React state‑management library that leverages hooks; its source code is concise and its API is straightforward. The article walks through the creation of a store, the underlying TypeScript types, middleware patterns, and answers a frequent question about memory leaks.

Store Creation

The store is created by calling create , which internally invokes createImpl and createStore to build the API object.

export const create = (
(createState: StateCreator
| undefined) =>
  createState ? createImpl(createState) : createImpl) as Create;

The optional createState parameter has the type StateCreator<T, [], []> | undefined . When provided, createImpl receives it; otherwise the raw createImpl function is returned for advanced configuration.

StateCreator Type

StateCreator defines the signature of a function that creates the initial state and optionally adds mutators.

export type StateCreator<
  T,
  Mis extends [StoreMutatorIdentifier, unknown][] = [],
  Mos extends [StoreMutatorIdentifier, unknown][] = [],
  U = T
> = ((
  setState: Get
, Mis>, "setState", never>,
  getState: Get
, Mis>, "getState", never>,
  store: Mutate
, Mis>
) => U) & { $$storeMutators?: Mos };

The generic parameters are:

T : type of the initial state.

Mis : list of input mutators.

Mos : list of output mutators.

U : return type, defaulting to T .

SetStateInternal

SetStateInternal<T> provides two overloads for partial updates and full replacements.

type SetStateInternal
= {
  _(partial: T | Partial
| { _(state: T): T | Partial
}["_"], replace?: false): void;
  _(state: T | { _(state: T): T }["_"], replace: true): void;
}["_"];

The first overload accepts a full state, a partial state, or a function that returns either; the second overload replaces the entire state when replace is true .

Utility Types: Get and Mutate

Get<T, K, F> extracts the type of key K from T or falls back to F if the key does not exist.

type Get
= K extends keyof T ? T[K] : F;

Mutate<S, Ms> recursively applies a list of mutators to a state type, enabling type‑safe extensions such as logging or timestamping.

export type Mutate
=
  number extends Ms["length" & keyof Ms] ? S :
  Ms extends [] ? S :
  Ms extends [[infer Mi, infer Ma], ...infer Mrs]
    ? Mutate
[Mi & StoreMutatorIdentifier], Mrs>
    : never;

Middleware Example

The article shows how to turn mutators into a middleware pipeline where each step can decide whether to call next .

function applyMiddlewares
(
  initialState: S,
  middlewaresList: Ms
): Mutate
{
  let index = 0;
  const execute = (state: S): S => {
    if (index >= middlewaresList.length) return state;
    const [mutatorId, action] = middlewaresList[index++];
    const mutator = mutators[mutatorId as StoreMutatorIdentifier];
    if (mutator) {
      return mutator(state, action, (newState) => execute(newState));
    }
    return execute(state);
  };
  return execute(initialState) as Mutate
;
}

Two concrete mutators— logging and timestamp —are defined, and the pipeline is invoked with:

const transformedState = applyMiddlewares
(
  initialState,
  [["logging", undefined], ["timestamp", undefined]]
);
console.log("Transformed state:", transformedState);

createImpl and useStore

createImpl builds the final hook that components call.

const createImpl =
(createState: StateCreator
) => {
  const api = createStore(createState);
  const useBoundStore: any = (selector?: any) => useStore(api, selector);
  Object.assign(useBoundStore, api);
  return useBoundStore;
};

The hook uses React's useSyncExternalStore to subscribe to state changes.

export function useStore
, U>(
  api: S,
  selector: (state: ExtractState
) => U
): U {
  const slice = React.useSyncExternalStore(
    api.subscribe,
    () => selector(api.getState()),
    () => selector(api.getInitialState())
  );
  React.useDebugValue(slice);
  return slice;
}

Memory‑Leak Concern

A common question is whether calling the hook repeatedly creates new stores. The answer is that create runs only once; the returned hook closes over a single store instance, and React’s subscription cleanup prevents leaks.

Conclusion

Zustand offers a minimal yet extensible state‑management solution for React, with strong TypeScript support, middleware capability, and efficient rendering via useSyncExternalStore . Understanding its core types and store‑creation flow not only helps build robust applications but also sharpens TypeScript skills.

References

Two‑image guide to React state‑management libraries: Zustand and Jotai

Zustand source‑code analysis

How reading Zustand’s source boosted my TypeScript proficiency

TypeScriptstate-managementReactmiddlewareZustand
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.