Skip to content

Instantly share code, notes, and snippets.

@niieani
Created April 21, 2018 06:08
Show Gist options
  • Save niieani/79cd42f80bd906540d2a31eab4bd58b5 to your computer and use it in GitHub Desktop.
Save niieani/79cd42f80bd906540d2a31eab4bd58b5 to your computer and use it in GitHub Desktop.
TypeScript hacks
type HasProperty<X, P> = (X[keyof X & P] extends P ? true : false) extends false ? true : false
type example = HasProperty<{type:1}, 'type'>
import {
combineReducers, createStore,
Action
} from 'redux'
type SiteState = {something: string}
const LOAD = 'LOAD'
const siteActions = {
[LOAD]: (state : SiteState | undefined, action : {type: typeof LOAD, baba: string}): SiteState => ({
...state!,
}),
['THING']: (state : SiteState | undefined, action : {type: 'THING', a: number}): SiteState => ({
...state!,
})
}
type StateFromReducersObject<T extends {
[type : string] : <S>(state : S | undefined, action : any) => S
}, Types extends keyof T = keyof T> = T extends {
[type : string] : (state : infer State | undefined, action : any) => infer State
} ? State : never
type BaseReducer<Type extends string> =
<State extends {}>(state : State | undefined, action : Action<Type>) => State;
type Reducer<Type extends string, Reducer extends (state : any, action : Action<Type>) => any = any> =
// type Reducer<Type extends string = '', Reducer extends Function = any> =
Reducer extends <State extends {}>(state : State | undefined, action : infer A) => State
? Reducer //& BaseReducer<Type>
: never; //BaseReducer<Type>;
type ActionFromReducer<Reducer extends (state : any, action : Action) => any = any> =
// type ActionFromReducer<Reducer extends Function = any> =
// Reducer extends (state: any, action: infer A) => any ? EnsureAction<A> : never;
Reducer extends (state: any, action: infer A) => any ? EnsureAction<A> : never;
type EnsureAction<A> = A //& {type: A[keyof A & 'type']}
const createReducer = (
<
Reducers extends {[Type in Types] : Reducer<Type>}, //& {[type: string]: Reducer<Type>},
Types extends keyof Reducers,
State = StateFromReducersObject<Reducers>,
MergedActions = ActionsFromReducers<Reducers>[keyof ActionsFromReducers<Reducers>],
// MergedActions extends Action = ActionFromReducer<Reducers[Types]>,
>(reducers : Reducers) =>
(state: State, action: MergedActions): State =>
(reducers as any)[(action as any).type](state, action)
// <Type extends keyof Reducers>(state: State, action: ActionFromReducer<Reducers[Type]>): State =>
// reducers[action.type](state, action)
)
const site = createReducer(siteActions);
site({something: 'abc'}, {type: "LOAD", baba: 'abc'})
// type Dupa = ActionFromReducer<typeof site>
// export type ReducersMapObject<
// Reducers extends {[Type in Types] : Reducer<Type>},
// Types extends keyof Reducers,
// A extends Action = Action
// > = {
// [K in keyof Reducers]: Reducer<A['type'], Reducers[K]>;
// }
// type MergeReducers = <
// Reducers extends { [Type in Types]: any; },
// Types extends keyof Reducers,
// State = Reducers extends {
// [type: string]: (state: infer State | undefined, action: any) => infer State;
// } ? State : never
// >(reducers: Reducers) =>
// <Type extends keyof Reducers>(
// state: State,
// action: (Reducers[Type] extends (state: any, action: infer Action) => any ? Action : never) & Action<Type>
// ) => State
type CombineReducers = <
Map extends {[Prefix in Prefixes]: (state: any, action: any) => any},
Prefixes extends keyof Map,
MergedState = {
readonly [Prefix in Prefixes]: ReturnType<Map[Prefix]>
},
MergedActions = MergedActionsFromReducers<Map>,
>(map: Map) =>
(state: MergedState | undefined, action: MergedActions) => MergedState
type GenericReducerMap<Map> = {[Prefix in keyof Map]: (state: any, action: any) => any}
type ActionsFromReducers<Map extends GenericReducerMap<Map>> = {
[Prefix in keyof Map]: ActionFromReducer<Map[Prefix]>
}
type MergedActionsFromReducers<Map extends GenericReducerMap<Map>> = ActionsFromReducers<Map>[keyof ActionsFromReducers<Map>]
declare var combine : CombineReducers
const toCombine = {
site
}
const reducer = combine(toCombine)
reducer({site: {something: 'hi'}}, {type: 'LOAD', baba: '123', x: 1})
// combineReducers
// export const store = createStore(reducer)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment