类型声明

在之前的章节中,已经出现了许多类型,这些类型在使用Typescript编写应用的时候十分有用。但是在一般情况下,编辑器和Typescript都是有自动类型推断功能的,所以并不需要吧每一个部分的类型都书写的十分清楚。

最简单的声明Store所使用的类型的方法就是如同以下示例中一样,利用类型参数化的create函数。

import create from 'zustand';
import { immer } from 'zustand/middleware';

interface GearBoxState {
  currentGear: number;
  shiftUp: () => void;
  shiftDown: () => void;
}

const useGearBox = create<GearBoxState>()(
  immer(set => ({
    currentGear: 0,
    shiftUp: () =>
      set(state => {
        state.currentGear += 1;
      }),
    shiftDown: () =>
      set(state => {
        state.currentGear -= 1;
      })
  }))
);

Warning

在使用类型参数化的create时,不是直接使用create<T>(set => ({}))的Store定义形式,而是create<T>()(set => ({})),不要丢了泛型参数之后的那一对括号。

以下提供一些在自定义Zustand中间件或者扩展功能的时候可能会用到的类型的定义。

// 所有声明中的State类型都是一个普通的对象。
type State = object;

// State片段就是实际上就是指定State类型的一部分,或者是返回一部分State类型内容的函数。
type ParitalState<T extends State> = Partial<T> | (state: T) => Partial<T>;

// 用于定义从State中选择指定内容的函数,可以是返回一个指定的State,也可以是返回使用指定的一组State组成的新数据结构,还可以是通过计算返回新的内容。
type StateSelector<T extends State, U> = (state: T) => U;

// 用于定义State是否相等的判断函数,主要用于控制State是否更改的判断。
type EqualityChecker<T> = (a: T, b: T) => boolean;

// 用于定义对State更变的监听器函数。
type StateListener<T> = (state: T, previousState: T) => void;

// 用于定义创建对指定Store监听的函数,以及监听注销的函数类型。
interface Subscribe<T extends State> {
  (listener: StateListener<T>): () => void;
}

// 定义set函数的类型,用于更新State。
type SetState<T extends State> = (
  partial: T | Partial<T> | ((state: T) => T | Partial<T>),
  replace?: boolean | undefined
) => void;

// 定义get函数的类型,用于从State中获取指定内容。
type GetState<T extends State> = () => T;

// 定义销毁Store的函数类型。
type Destory = () => void;

// 定义在原生Javascript中定义出的Store类型与组成。这也是一个Store中比较基本的底层功能。
interface StoreApi<T extends State> {
  setState: SetState<T>;
  getState: GetState<T>;
  subscribe: Subscribe<T>;
  destory: Destory;
}

// 定义Store中状态的名称,其中StoreMutator就是一个普通的对象,
type StoreMutatorIdentifier = keyof StoreMutator<unknown, unknown>;

// 定义Store中的可变对象,也就是状态。
type Mutate<S, Ms> = Ms extends []
  ? S
  : Ms extends [[infer Mi, infer Ma], ...infer Ms]
  ? Mutator<StoreMutators<S, Ma>[Mi & StoreMutatorIdentifier], Ms>
  : never;

type Get<T, K, F = never> = K extends keyof T ? T[K] : F;

// 定义用于创建Store的函数类型。也就是create函数中所使用的函数类型。
type StateCreator<
  T extends State,
  Mis extends [StoreMutatorIdentifier, unknown][] = [],
  Mos extends [StoreMutatorIdentifier, unknown][] = [],
  U = T
> = ((
  setState: Get<Mutate<StoreApi<T>, Mis>, 'setState', undefined>,
  getState: Get<Mutate<StoreApi<T>, Mos>, 'getState', undefined>,
  store: Mutate<StoreApi<T>, Mis>,
) => U);

// 定义create函数的类型声明,可以看到create函数是可以接受一个StateCreator类型的函数作为Store的初始化函数的。
// 同时,用于定义中间件的函数类型也是采用的这个类型。
interface CreateStore {
  <T extends State, Mos extends [StoreMutatorIdentifier, unknown][] = []>(
    initializer: StateCreator<T, [], Mos>
  ): Mutate<StoreApi<T>, Mos>;

  <T extends State>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(
    initializer: StateCreator<T, [], Mos>
  ) => Mutate<StoreApi<T>, Mos>;
}

// 工具类型,用于定义允许提取状态的类型限定。
type ExtractState<S> = S extends { getState: () => infer T } ? T : never;
//工具类型,用于定义适用于React的内容类型。
type WithReact<S extends StoreApi<State>> = S & {
  getServerState?: () => ExtractState<S>;
}

// 定义Store Hook的类型,可以看到Store Hook可以直接返回State,或者使用选择器返回要选择的内容。
type UseBoundStore<S extends WithReact<StoreApi<State>>> = {
  (): ExtractState<S>;
  <U>(
    selector: StateSelector<ExtractState<S>, U>,
    equals: EqualityChecker<U>
  ): U
} & S;

上面这些类型定义中有一部分是Zustand中所使用到的工具类型,为了保证能够顺利阅读所有常用的类型,故一并摘抄了进来。在实际项目使用中,可以从其中选择所需要的类型使用。