/** @module function/evolve.ts */ import { AnyObject, DeepPartial, DeepPartialFlexibleType } from '../helper-types' // import { trace } from '../logging' import { assoc, path } from '../object' import { Evolve } from '../type/evolve-type' import { type } from '../type/type' import { untypedCurry } from './untypedCurry' const _evolveReducer = ( fno: {}, prev: {}, dao: {}, keyList: string[] ) => Object.entries( dao ).reduce( ( acc, [ key, val ] ) => type( fno[ key ] ) !== 'Function' ? type( fno[ key ] ) === 'Object' && type( val ) === 'Object' ? assoc( acc, key, _evolveReducer( fno[ key ], prev, val, keyList.concat( key ) ) ) : assoc( acc, key, val ) : assoc( acc, key, fno[ key ]( val, path( keyList.concat( key ) as any, prev ) ) ) , {} ) const _evolveReducer2 = ( fno: {}, prev: {}, dao: {} ) => ( {...prev, ..._evolveReducer( fno, prev, dao, [] )} ) /* The way redux works is you give a reducer and initial state. Dispatch trigger some type with some qualifier. The reducer is given the last resolved total state and the dispatched action. Evolve has some functions. It will be given the last computed state (or inital state) and the current */ interface EvolveReducerSecondParameterCurried {

>( previousState: P, incoming: I ): Evolve

>( previousState: P ): ( incoming: I ) => Evolve } /** * Produces a new object from the result of applying function from an * object tree with functions which take corresponding values from an * incoming object * @param evolver * @param incoming */ export function evolveReducer = DeepPartial

>( evolver: E, previousState: P, incoming: I ): P // export function evolveReducer( evolver: E ): EvolveReducerSecondParameterCurried export function evolveReducer( ...args ) { return untypedCurry( _evolveReducer2 )( ...args ) } // evolveReducer( { // x: { // y: ( x: number, y: number ) => 400, // }, // }, { w: 100, x: { y: 10 } }, {p: 4, w: '30' } ) // interface Foo { // a: { // b: number, // }, // c: number // } // declare function foo( // obj: O, // part: P, // ): P // const sdf = foo( {a: 1}, {b: 2} ) // type Bro = DeepPartial // declare function TT( p: I, foo: Partial ): boolean // TT( {h: 4}, { h: 3, a: { b: 4} } ) // declare function foo>( obj: O, part: P ): P // foo( { a: { b: 3 }}, { p: 44, a: { b: 3}} ) type StrictPartial = { [K in keyof P]: K extends keyof O ? O[K] : never } export type StrictDeepPartial = { [K in keyof P]: K extends keyof O ? O[K] extends Array ? never // Array> : O[K] extends ReadonlyArray ? ReadonlyArray> : P[K] : never } // When you resume this, check out this gist // https://gist.github.com/babakness/a1ca775f81097ffae04098a8cfdadc60 // declare function foo2>( // obj: O, // part: P, // ): P // const bro = foo2( { a: { b: 3 }}, { a: { b: '3'}} )