HenrikJoreteg / redux-bundler

Compose a Redux store out of smaller bundles of functionality.
https://reduxbundler.com
583 stars 46 forks source link

[Feature request] Typescript types #69

Open vujita opened 4 years ago

vujita commented 4 years ago

After a quick look this repo and the build tool being used microbundle now supports typescript.

It would be nice to allow for this type of support

I have a quick and dirty branch of something like this

https://github.com/vujita/redux-bundler/tree/typscript

HenrikJoreteg commented 4 years ago

Not really sold on this idea. I just don't think there's that much of a win. I looked at the repo you linked to and didn't see many types, what am I missing?

vujita commented 4 years ago

I'm sorry, I forgot the dist folder will be git ignored. The types are inferred from the previous code written. My example was to help define the scope of changes needed to introduce the changes

image

rraihansaputra commented 3 years ago

On Typescript: As I understand it, properly typing redux-bundler would be really hard if not impossible (due to the string based calls etc) (and mentioned on the above issue https://github.com/ipfs-shipyard/ipfs-webui/pull/1589/files/448a28c42ad1e15b7d963428db8fb38ae63ca513#r489769808).

What I think is worth it to be discussed is partial typing or just more information support regarding the actions and selectors. 2 high impact points:

  1. It would be really helpful to have autocompletes/a list of eligible selectors/actions to be connected. I think it can be done by filtering the bundle exports. It may even unlock the return type of the selectors too.
  2. On the connector side, it would be really helpful to have return annotations to help autocomplete with the returned selector and action keys.

I don't have a lot of experience in typing libraries yet, but I would like to try my hand on it.

Note: on the other side I have a successful PoC of redux-bundler-svelte, and it would be really great to have typescript IntelliSense on it too.

cunningryan commented 2 years ago

I know it's not a priority for the project, but for those interested I think there's hope with some TypeScript updates... This PR for TypeScript 4.4 allows the use of template literal strings for type keys. That allows something like this (one step in adding types to this lib)...

type BundleType = {
  name: string;
  getReducer: GetReducerType;
  [key: `select${string}`]: SelectorType;
  [key: `do${string}`]: ActionCreatorType;
  [key: `react${string}`]: ReactorType;
};

Not asking for it to be added to the project, just sharing as someone who loves redux-bundler and has gotten more TypeScript work over the past year or so. And I'm hoping to get the best of both along the way. Doing some playing around now to see how far this can go. The string-based calls on the other side provide another fun challenge, so just following the path and seeing if any of the TS changes help us out.

HenrikJoreteg commented 2 years ago

I've been playing around with typing apps using a .d.ts file.

The following works OK:

declare global {
  type Reducer = (state: any, { type: string, payload: any }) => state

  // starting with defining the things that get injected by connect
  type Store = {
    activeOrgId: string
    activeOrgLoading: boolean
    practitioners: Practitioner
    locations: Location[] | null
    userWelcomeMode: UserWelcomeMode
    needsLocations: boolean
    isOnboarding: boolean
    appointments: Appointment[] | null
    needsOtherMembers: boolean
    needsAppointments: boolean
    onboardingSteps: OnboardingSteps | null
    onboardingPercentage: number
    orgFetchedInitialResources: boolean
    userHasMFASetUp: boolean
    nextOnboardingStep: OnboardingStep | null
    canCreateCase: boolean
    needsBAA: boolean
    isPossiblyOnboarding: boolean
    sessionOrgs: OrgMembership[] | null
    breadCrumbs: Breadcrumb[] | null
    subscriptionStatus: OrgSubscriptionStatus
    isOrgAdmin: boolean
  }

  // this maps the keys above to their selector names
  type WithSelectorNames<Type> = {
    [Property in keyof Type as `select${Capitalize<
      string & Property
    >}`]: () => Type[Property]
  }

  // then you can get a store object w/ selector names
  type MetaStore = WithSelectorNames<Store>

  // and kinda define a bundle by joining that meta store 
  // to build a bundle type
  type Bundle = Partial<MetaStore> & {
    name: string
    reducer?: Reducer
    getReducer?: () => Reducer
  }
}

// defining them individually like this for connect kinda sucks
// it lets you do an set number of selectors and then still retain
// the types in the connected function
export function connect(selector1: keyof MetaStore, fn: (store: Store) => any)
export function connect(
  selector1: keyof MetaStore,
  selector2: keyof MetaStore,
  fn: (store: Store) => any
)
export function connect(
  selector1: keyof MetaStore,
  selector2: keyof MetaStore,
  selector3: keyof MetaStore,
  fn: (store: Store) => any
)
export function connect(
  selector1: keyof MetaStore,
  selector2: keyof MetaStore,
  selector3: keyof MetaStore,
  selector4: keyof MetaStore,
  fn: (store: Store) => any
)
export function connect(
  selector1: keyof MetaStore,
  selector2: keyof MetaStore,
  selector3: keyof MetaStore,
  selector4: keyof MetaStore,
  selector5: keyof MetaStore,
  fn: (store: Store) => any
)
export function connect(
  selector1: keyof MetaStore,
  selector2: keyof MetaStore,
  selector3: keyof MetaStore,
  selector4: keyof MetaStore,
  selector5: keyof MetaStore,
  selector6: keyof MetaStore,
  fn: (store: Store) => any
)

I've also toyed around w/ adding types for these into JS projects by defining a "typed connect" and just importing that instead of raw "connect".

Basically defining a module like this:

//@ts-check
import { connect } from 'redux-bundler-preact'
/** @type {import('../../types').connect} */
export const smartConnect = connect

It gives you this type of experience:

Screen Shot 2021-07-23 at 8 56 38 AM

Then, when you de-structure it to use the selected values they retain their types:

Screen Shot 2021-07-23 at 8 57 11 AM
cunningryan commented 2 years ago

That's awesome and very helpful, thanks! I've got a .d.ts file I've started on the "other" side with types for the redux-bundler lib itself. I'll share here when I get something that feels like a decent starting point on that part.

rraihansaputra commented 2 years ago

Great to see this is being opened again. I've also done some work with typing on my own apps, both on the connect and the store itself. TS 4.4 opens up a lot of possibilities for a @types/redux-bundler or a d.ts for redux-bundler to be implemented and enforce type safety for bundles.