DEV Community

Cover image for Why Zustand Typescript Implementation Is So Ugly
Daishi Kato
Daishi Kato

Posted on • Edited on • Originally published at blog.axlight.com

1

Why Zustand Typescript Implementation Is So Ugly

BTW, JavaScript implementation is so clean

Introduction

Note: This post focuses on Zustand library's implementation in TypeScript. It does not affect the user code, which should be kept clean.

Zustand's JavaScript implementation is very small, as seen in the following tweet.

However, its TypeScript implementation is quite complicated. There are several reasons, one of which we explore in this post.

SetStateInternal type

Let's take a closer look at the SetStateInternal type.

(Keep in mind that it's intended for internal use, as we recommend using StoreApi['setState'] for public APIs.)

https://github.com/pmndrs/zustand/blob/f11cc7f37ad0a53f49370c0e4e659690a1c1a721/src/vanilla.ts#L1-L6

type SetStateInternal<T> = {
  _(
    partial: T | Partial<T> | { _(state: T): T | Partial<T> }['_'],
    replace?: boolean | undefined
  ): void
}['_']
Enter fullscreen mode Exit fullscreen mode

What are those simily characters ['_']?

It's a TypeScript hack, and the actual character used (in this case, _) is not significant; any word would work. We don't go into TypeScript technical details, but let's see what happens if we don't use such a hack.

What we would imagine is the following type as a simpler alternative.

type SetStateInternal2<T> = (
  partial: T | Partial<T> | ((state: T) => T | Partial<T>),
  replace?: boolean | undefined
) => void
Enter fullscreen mode Exit fullscreen mode

This doesn't work for certain cases. Let's explore how it fails with contrived examples.

The first one is the following:

type State = { name: string; age: number };

declare function run<Fn extends SetStateInternal<unknown>>(fn: Fn): void;
declare function run2<Fn extends SetStateInternal2<unknown>>(fn: Fn): void;
declare const setState: SetStateInternal<State>
declare const setState2: SetStateInternal2<State>
run(setState);
run2(setState2);
Enter fullscreen mode Exit fullscreen mode

run2 causes a type error.

The second one is the following:

type NameOnlyState = { name: string };
type StoreApi<T> = { setState: SetStateInternal<T> };
type StoreApi2<T> = { setState: SetStateInternal2<T> };
declare const store: StoreApi<State>;
declare const store2: StoreApi2<State>;
const nameOnlyStore: StoreApi<NameOnlyState> = store;
const nameOnlyStore2: StoreApi2<NameOnlyState> = store2;
Enter fullscreen mode Exit fullscreen mode

Assigning to nameOnlyStore2 fails.

You can find the full reproduction in the TypeScript playground: https://tsplay.dev/NBVO4N

As a library consumer, you don't need to know why this happens or how to resolve it. It's something TypeScript magicians should take care of.

Closing notes

This post has highlighted one of the reasons behind the complexity of Zustand's TypeScript implementation. There are other reasons, which could be addressed in a future post.


Originally published at https://blog.axlight.com on July 19, 2023.

Sentry blog image

How to reduce TTFB

In the past few years in the web dev world, we’ve seen a significant push towards rendering our websites on the server. Doing so is better for SEO and performs better on low-powered devices, but one thing we had to sacrifice is TTFB.

In this article, we’ll see how we can identify what makes our TTFB high so we can fix it.

Read more

Top comments (0)

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post

Best practices for optimal infrastructure performance with Magento

Running a Magento store? Struggling with performance bottlenecks? Join us and get actionable insights and real-world strategies to keep your store fast and reliable.

Tune in to the full event

DEV is partnering to bring live events to the community. Join us or dismiss this billboard if you're not interested. ❤️