Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Typings #36

Open
kennetpostigo opened this issue Mar 8, 2020 · 12 comments
Open

Typings #36

kennetpostigo opened this issue Mar 8, 2020 · 12 comments

Comments

@kennetpostigo
Copy link

Is there anyway we can get some typescript definitions for this library?

@jamesplease
Copy link
Collaborator

iirc @chrisdhanaraj has some he may be able to share

@chrisdhanaraj
Copy link
Contributor

Yes! I'll open a PR tomorrow to definitely typed and cc you both

@kennetpostigo
Copy link
Author

@chrisdhanaraj any chance I can get a copy of your types to add to my local type defs?

@jamesplease
Copy link
Collaborator

I found the link he sent to me with the typings, but I’ll need to wait til tomorrow to post em here as I’m not on my work computer.

@jamesplease
Copy link
Collaborator

These may not be for the latest version of the lib, but here's what Chris sent me a few months back:

/* eslint-disable @typescript-eslint/no-explicit-any */

declare module 'use-reducer-with-side-effects' {
  import { Dispatch } from 'react';
  // useCreateReducerWithEffect has a different signature than the original reducer
  // so need to redeclare each of these properties

  type Reducer<S, A> = (prevState: S, action: A) => ReducerReturn<S, A> | symbol;
  type ReducerState<R extends Reducer<any, any>> = R extends Reducer<infer S, any> ? S : never;
  type ReducerAction<R extends Reducer<any, any>> = R extends Reducer<any, infer A> ? A : never;

  export type ReducerReturnBeta<S, A> =
    | UpdateReturn<S>
    | symbol
    | SideEffectReturn<S, A>
    | UpdateWithSideEffectReturn<S, A>;

  export interface ReducerReturn<S, A> {
    newState?: S;
    newSideEffect?: SideEffectCallback<S, A>;
  }

  export type SideEffectCallback<S, A> = (state: S, dispatch: Dispatch<A>) => void;

  export interface UpdateReturn<S> {
    newState: S;
  }

  export function Update<S>(newState: S): UpdateReturn<S>;

  export function NoUpdate(): symbol;

  export interface SideEffectReturn<S, A> {
    newSideEffect: SideEffectCallback<S, A>;
  }
  export function SideEffect<S, A>(state: S, dispatch: Dispatch<A>): SideEffectReturn<S, A>;

  export interface UpdateWithSideEffectReturn<S, A> {
    newState: S;
    newSideEffect: SideEffectCallback<S, A>;
  }

  export interface DefaultInitState<I> {
    sideEffects: [];
    state: I;
  }

  export function UpdateWithSideEffect<S, A>(
    newState: S,
    newSideEffect: SideEffectCallback<S, A>
  ): UpdateWithSideEffectReturn<S, A>;

  export default function useCreateReducerWithEffect<R extends Reducer<any, any>, I>(
    reducer: R,
    initializerArg: I,
    initializer?: undefined
  ): [ReducerState<R>, Dispatch<ReducerAction<R>>];

  export default function useCreateReducerWithEffect<R extends Reducer<any, any>, I>(
    reducer: R,
    initializerArg: I,
    initializer: (init: DefaultInitState<I>) => DefaultInitState<I>
  ): [ReducerState<R>, Dispatch<ReducerAction<R>>];
}

@chrisdhanaraj
Copy link
Contributor

chrisdhanaraj commented Mar 13, 2020 via email

@kennetpostigo
Copy link
Author

@jamesplease Thank you! Will use those for now! 🙏

@chrisdhanaraj
Copy link
Contributor

chrisdhanaraj commented Mar 14, 2020

@kennetpostigo I AM SO SORRY, oh my god, try these on

declare module "use-reducer-with-side-effects" {
  export type ReducerReturn<ReducerState, ReducerActions> =
    | symbol
    | UpdateReturn<ReducerState>
    | SideEffectReturn<ReducerState, ReducerActions>
    | UpdateWithSideEffectReturn<ReducerState, ReducerActions>;

  export type Reducer<ReducerState, ReducerActions> = (
    state: ReducerState,
    action: ReducerActions
  ) => ReducerReturn<ReducerState, ReducerActions>;

  export type Dispatch<ReducerActions> = (action: ReducerActions) => void;

  export interface StateShape<ReducerState> {
    sideEffects: any[];
    state: ReducerState;
  }

  export type CancelFunction = () => void;
  export type SideEffectCallback<ReducerState, ReducerActions> = (
    state: ReducerState,
    dispatch: Dispatch<ReducerActions>
  ) => void | CancelFunction;

  export function NoUpdate(): symbol;

  export interface SideEffectReturn<ReducerState, ReducerActions> {
    sideEffects: SideEffectCallback<ReducerState, ReducerActions>[];
  }

  export function SideEffect<ReducerState, ReducerActions>(
    args: SideEffectCallback<ReducerState, ReducerActions>
  ): SideEffectReturn<ReducerState, ReducerActions>;

  export interface UpdateReturn<ReducerState> {
    state: ReducerState;
  }

  export function Update<ReducerState>(
    state: ReducerState
  ): UpdateReturn<ReducerState>;

  export interface UpdateWithSideEffectReturn<ReducerState, ReducerActions> {
    state: ReducerState;
    sideEffects: SideEffectCallback<ReducerState, ReducerActions>[];
  }

  export function UpdateWithSideEffect<ReducerState, ReducerActions>(
    state: any,
    sideEffects: SideEffectCallback<ReducerState, ReducerActions>
  ): UpdateWithSideEffectReturn<ReducerState, ReducerActions>;

  export default function useCreateReducerWithEffect<
    ReducerState,
    ReducerActions
  >(
    reducer: Reducer<ReducerState, ReducerActions>,
    initializerArg: ReducerState,
    initializer?: (args: StateShape<ReducerState>) => StateShape<ReducerState>
  ): [ReducerState, Dispatch<ReducerActions>];
}

@kennetpostigo
Copy link
Author

Thank you @chrisdhanaraj!

@szg251
Copy link

szg251 commented May 11, 2020

I added type definitions to the library itself in a PR and I currently use the generated definitions in one of my projects:

import { Dispatch } from "react"

declare module "use-reducer-with-side-effects" {
  export declare type ReducerWithSideEffects<S, A> = (
    prevState: S,
    action: A | NoUpdateSymbol
  ) => Partial<StateWithSideEffects<S, A>> | NoUpdateSymbol
  export declare type StateWithSideEffects<S, A> = {
    state: S
    sideEffects: SideEffect<S, A>[]
  }
  export declare type SideEffect<S, A> = (
    state: S,
    dispatch: Dispatch<A>
  ) => Promise<void> | void | CancelFunc<S>
  export declare type CancelFunc<S> = (state: S) => void
  export declare type NoUpdateSymbol = typeof NO_UPDATE_SYMBOL
  export declare const NO_UPDATE_SYMBOL: unique symbol
  export declare const Update: <S>(
    state: S
  ) => {
    state: S
  }
  export declare const NoUpdate: () => typeof NO_UPDATE_SYMBOL
  export declare const UpdateWithSideEffect: <S, A>(
    state: S,
    sideEffects: SideEffect<S, A>[]
  ) => {
    state: S
    sideEffects: SideEffect<S, A>[]
  }
  export declare const SideEffect: <S, A>(
    sideEffects: SideEffect<S, A>[]
  ) => {
    sideEffects: SideEffect<S, A>[]
  }
  export declare function executeSideEffects<S, A>({
    sideEffects,
    state,
    dispatch,
  }: {
    sideEffects: SideEffect<S, A>[]
    state: S
    dispatch: Dispatch<A>
  }): Promise<CancelFunc<S>[]>
  export declare function mergeState<S, A>(
    prevState: StateWithSideEffects<S, A>,
    newState: Partial<StateWithSideEffects<S, A>> | NoUpdateSymbol,
    isUpdate: boolean
  ): StateWithSideEffects<S, A>
  export default function useCreateReducerWithEffect<S, A>(
    reducer: ReducerWithSideEffects<S, A>,
    initialState: S,
    init?: (state: S) => Partial<StateWithSideEffects<S, A>>
  ): [S, Dispatch<A | NoUpdateSymbol>]
  export declare function composeReducers<S, A>(
    reducers: ReducerWithSideEffects<S, A>[]
  ): (
    state: S,
    action: A
  ) =>
    | typeof NO_UPDATE_SYMBOL
    | {
        state: S | undefined
        sideEffects: SideEffect<S, A>[]
      }
}

@stuckj
Copy link

stuckj commented Apr 22, 2021

FYI, typings from @gege251 and @chrisdhanaraj have a minor difference from @conorhastings's implementation. In the UpdateWithSideEffect function, the sideEffects parameter may be EITHER a function OR an array of functions. This applies to the SideEffect function as well. You can see this in the mergeState function in the library (this line).

Here are updated types for UpdateWithSideEffect and SideEffect that handle both cases.

  export function SideEffect<ReducerState, ReducerActions>(
    args:
      | SideEffectCallback<ReducerState, ReducerActions>[]
      | SideEffectCallback<ReducerState, ReducerActions>
  ): SideEffectReturn<ReducerState, ReducerActions>

  export function UpdateWithSideEffect<ReducerState, ReducerActions>(
    state: any,
    sideEffects:
      | SideEffectCallback<ReducerState, ReducerActions>[]
      | SideEffectCallback<ReducerState, ReducerActions>
  ): UpdateWithSideEffectReturn<ReducerState, ReducerActions>

It's the same idea for @gege251's types but with the shorter generic parameters.

As an aside. Is there any problem with just adding a use-reducer-with-side-effects.d.ts file into the library without typescript support (as @gege251 had added in his PR) to make this easier for everyone using typescript? I'm fairly new to typescript so I didn't know if just the presence of the type definitions in the library was sufficient (it seems to be in the individual project). That seems like a far less obtrusive change that I'm assuming @conorhastings would be ok with pulling in since it literally doesn't change any existing code.

If anyone more familiar can chime in as to whether that's enough for adding typing then I'm happy to throw what I've got working from my project into a .d.ts file and make a PR.

@stuckj
Copy link

stuckj commented May 12, 2021

Made a PR for this here: #45. I believe just using index.d.ts should work from what I read up about this on typescript. The alternative to putting this in the library is to submit it to DefinitelyTypes which should also work as long as you add @types/node to your project (if doing a node project).

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants