Open vujita opened 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?
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
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:
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.
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.
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:
Then, when you de-structure it to use the selected values they retain their types:
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.
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.
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