Repository: pmndrs/zustand
File: src/index.ts (TypeScript)

Code before:
export type StateListener<T extends State, U = T> = (state: U) => void
export type StateSelector<T extends State, U> = (state: T) => U
export type PartialState<T extends State> =
  | Partial<T>
  | ((state: T) => Partial<T>)
export type SetState<T extends State> = (partial: PartialState<T>) => void
export type GetState<T extends State> = () => T

export interface Subscribe<T> {
  (listener: StateListener<T>): () => void
  <U>(selector: StateSelector<T, U>, listener: StateListener<T, U>): () => void
}
export interface UseStore<T> {
  (): T
  <U>(selector: StateSelector<T, U>, dependencies?: ReadonlyArray<any>): U
}
export interface StoreApi<T> {
  getState: GetState<T>
  setState: SetState<T>
  subscribe: Subscribe<T>
  destroy: () => void
}

const reducer = <T>(state: any, newState: T) => newState

export default function create<TState extends State>(
  createState: (set: SetState<State>, get: GetState<State>, api: any) => TState
): [UseStore<TState>, StoreApi<TState>] {
  const listeners: Set<StateListener<TState>> = new Set()

  const setState: SetState<TState> = partial => {
    const partialState =
      typeof partial === 'function' ? partial(state) : partial
    if (partialState !== state) {
      state = Object.assign({}, state, partialState)
      listeners.forEach(listener => listener(state))
    }
  }

  const getState: GetState<TState> = () => state

  // Optional selector param goes first so we can infer its return type and use
  // it for listener
  const subscribe: Subscribe<TState> = <TStateSlice>(
    selectorOrListener:
      | StateListener<TState>
      | StateSelector<TState, TStateSlice>,
    listenerOrUndef?: StateListener<TState, TStateSlice>
  ) => {
    let listener = selectorOrListener
    // Existance of second param means a selector was passed in

Review comment (suggestion):
Just to understand, is it to detect if we're in JS vs TS land? I'm curious about that `extends never` bit.

I just tested it and it does fix the type inference issue in TS. We still have to pass the state generic explicitely to `create` to not get implicit anys but I think that's a good DX behaviour.

Code after:
  | Partial<T>
  | ((state: T) => Partial<T>)
export type SetState<T extends State> = (partial: PartialState<T>) => void
export type GetState<T extends State> = () => T

export interface Subscribe<T> {
  (listener: StateListener<T>): () => void
  <U>(selector: StateSelector<T, U>, listener: StateListener<T, U>): () => void
}
export interface UseStore<T> {
  (): T
  <U>(selector: StateSelector<T, U>, dependencies?: ReadonlyArray<any>): U
}
export interface StoreApi<T> {
  getState: GetState<T>
  setState: SetState<T>
  subscribe: Subscribe<T>
  destroy: () => void
}

const reducer = <T>(state: any, newState: T) => newState
const useIsomorphicLayoutEffect =
  typeof window !== 'undefined' ? useLayoutEffect : useEffect

export default function create<TState extends State>(
  createState: keyof TState extends never
    ? (set: any, get: any, api: any) => TState
    : (set: SetState<TState>, get: GetState<TState>, api: any) => TState
): [UseStore<TState>, StoreApi<TState>] {
  const listeners: Set<StateListener<TState>> = new Set()

  const setState: SetState<TState> = partial => {
    const partialState =
      typeof partial === 'function' ? partial(state) : partial
    if (partialState !== state) {
      state = Object.assign({}, state, partialState)
      listeners.forEach(listener => listener(state))
    }
  }

  const getState: GetState<TState> = () => state

  // Optional selector param goes first so we can infer its return type and use
  // it for listener
  const subscribe: Subscribe<TState> = <TStateSlice>(
    selectorOrListener:
      | StateListener<TState>
      | StateSelector<TState, TStateSlice>,
    listenerOrUndef?: StateListener<TState, TStateSlice>
  ) => {
    let listener = selectorOrListener