TypeScript探秘:一段 zustand 源码的奇妙旅程

哈喽大家好,我是Range。上次分享的typescript使用技巧,很多同学表示很有用,解决了实际开发中的很多疑惑。今天再带来一篇关于typescript的文章,从基础的用法开始,到zustand类库里的一些高级用法,希望大家能进一步理解typescript,拒绝 any 党。

下面是正文部分。



TypeScript探秘:一段 zustand 源码的奇妙旅程

在编程世界的某个安静角落,TypeScript(TS)以其强大的类型系统静静地守护着代码的纯洁和安全。在这段探索旅程中,我们将跟随一个好奇心旺盛的开发者的脚步,一探 zustand 库的源码深处,揭开 TS 类型推断的神秘面纱。

类型推断:TS 的无声守护者

TS 的两大法宝——类型约束和类型推断,就像是编程世界的守夜人。类型约束确保我们的代码在破晓前就远离了语法的怪兽,而类型推断则是那位在幕后默默工作的智者,它用无形的手指引编译器,让变量的类型在没有明确声明的情况下也能被精准地识别。

变量的自我发现之旅

想象一下,变量是一群渴望被发现的探险家,它们带着初始的宝藏(值)出发,而 TS 的类型推断就是那神秘的地图,总能引领它们找到真正的自我(类型)。

let numArray: number[] = [123];
let str: string = 'hello';
变量自我发现
类型地图

函数的多面镜

函数是 TS 世界的多面镜,它们不仅反射出自身的类型,还能在条件分支中展现出多重身份。每一面镜子都映照出一个可能的返回类型,而 TS 智者总能巧妙地将这些身份融合为一个联合体。

function getFirstItem(array: number[] | string[]): number | string {
  return array[0];
}
多面镜

泛型的魔法

泛型是 TS 世界的魔法,它赋予了代码以无穷的变化和灵活性。通过泛型,我们可以创造出能够适应任何类型的神奇函数,就像一个万能钥匙,打开了类型安全的大门。

function pick<TK extends keyof T>(obj: T, keys: K[]): Partial<T{
  const result: Partial<T> = {} as any;
  for (const key of keys) {
    result[key] = obj[key];
  }
  return result;
}
泛型魔法

实战演练

挑选属性的 pick 法术

在对象的海洋中,我们需要一种法术来挑选出我们所需要的属性。这就是 pick 方法,一个简单而强大的咒语,能够让我们在众多属性中找到那一颗璀璨的珍珠。

interface User {
  name: string;
  age: number;
}

type UserSubset = 'name' | 'age';

function getUserSubset(user: User, keys: UserSubset[]): Pick<UserUserSubset>;
pick 法术

useRequest 钩子的奇遇

在一个充满异步请求的王国里,useRequest 钩子是一位勇敢的骑士,它保护我们的数据在获取过程中不受干扰。通过它的守护,我们的数据总是安全地被加载和展示。

import { useEffect, useState } from 'react';

// 模拟请求接口,返回用户列表
function getUsers(): Promise<{ name: string }[]> {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve([
        {
          name: 'tom',
        },
        {
          name: 'jack',
        },
      ]);
    }, 1000);
  })
}

const App = () => {
  const [users, setUsers] = useState<Awaited<ReturnType<typeof getUsers>>>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(false);

  useEffect(() => {
    setLoading(true);
    getUsers().then((res) => {
      setUsers(res);
    }).catch(() => {
      setError(true);
    }).finally(() => {
      setLoading(false);
    })
  }, []);

  if (loading) {
    return <div>loading...</div>;
  }

  if (error) {
    return <div>error</
div>;
  }

  return (
    <div>
      {users.map(u => (
        <div key={u.name}>{u.name}</div>
      ))}
    </
div>
  );
};

export default App;
useRequest 钩子

zustand 库的源码探秘

zustand 库是 React 世界的一块宝石,它的状态管理能力让无数开发者为之倾倒。让我们一起深入它的源码,探索 TS 类型定义的奥秘。

在这段源码的探秘中,我们首先会遇到 create 方法,它是 zustand 库的心脏,负责初始化我们的状态和动作。通过这个方法,我们可以定义一个状态机,它能够响应各种操作并保持数据的一致性。

export const useStore = create<State & Action>((set) => ({
  count: 1,
  inc: () => set((state) => ({ count: state.count + 1 })),
}
)
);
zustand 源码

create 方法的定义是一系列重载的函数,它们允许我们以不同的方式定义状态和动作。这些重载函数的类型定义是如此精妙,以至于它们能够适应各种复杂的场景,同时保持类型的准确性和灵活性。

type Create = {
  <T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(
    initializer: StateCreator<T, [], Mos>,
  ): UseBoundStore<Mutate<StoreApi<T>, Mos>>;
  <T>() => <Mos extends [StoreMutatorIdentifier, unknown][] = []>(
    initializer: StateCreator<T, [], Mos>,
  ) => UseBoundStore<Mutate<StoreApi<T>, Mos>>,
  /**
   * @deprecated Use `useStore` hook to bind store
   */

  <S extends StoreApi<unknown>>(store: S): UseBoundStore<S>
};

在 zustand 库的类型定义中,我们还可以定义中间件,这些中间件可以改变 store 的行为,同时保持类型的准确性。

import { StateCreator, StoreMutatorIdentifier } from 'zustand';

type Test = <
  T,
  Mps extends [StoreMutatorIdentifier, unknown][] = [],
  Mcs extends [StoreMutatorIdentifier, unknown][] = [],
  U = T
>(
  initializer: StateCreator<T, [...Mps, ['test', unknown]], Mcs>
) => StateCreator<T, Mps, [['test', U], ...Mcs]>;

type Write<T, U> = Omit<T, keyof U> & U;

declare module 'zustand' {
  interface StoreMutators<S, A> {
    test: Write<S, {test: {log: () => void}}>;
  }
}

function a({
  console.log(444);
}

export const test = a as unknown as Test;
中间件类型定义

总结:TS 的魔法之旅

通过这段旅程,我们不仅领略了 TypeScript 类型推断的魅力,还深入探索了 zustand 库的源码。这一路上,我们学会了如何使用 TS 的类型系统来编写更加安全、灵活和可维护的代码。就像所有的探险故事一样,我们的旅程也许结束了,但 TS 的魔法和 zustand 的奇妙世界仍将继续引领我们走向更多的发现和创造。

最后

还没有使用过我们刷题网站(https://fe.ecool.fun/)或者前端面试题宝典的同学,如果近期准备或者正在找工作,千万不要错过,题库主打无广告和更新快哦~。

老规矩,也给我们团队的辅导服务打个广告。