Created
January 3, 2019 00:30
-
-
Save desmondrawls/3c4bb92a2eb8d67223b4c5e46ae210dd to your computer and use it in GitHub Desktop.
type safe paths for use with redux
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Path, State, initialState } from "./PathFinder"; | |
describe('PathFinder', () => { | |
it('works', () => { | |
let actual = new Path<State>(initialState).path("driverInfo").path("gender").action("unicorn"); | |
expect(actual.payload).toEqual({ "driverInfo": { "gender": "unicorn" } }); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const initialState = { | |
driverInfo: { | |
firstName: '', | |
lastName: '', | |
gender: '' | |
}, | |
products: { | |
low: { | |
price: 99, | |
coverage: "not much coverage" | |
}, | |
middle: { | |
price: 150, | |
coverage: "some coverage" | |
}, | |
high: { | |
price: 200, | |
coverage: "lots of coverage" | |
} | |
} | |
} | |
export type State = Readonly<typeof initialState> | |
type DeepPartial<T> = { | |
[P in keyof T]?: T[P] extends Array<infer U> | |
? Array<DeepPartial<U>> | |
: T[P] extends ReadonlyArray<infer U> | |
? ReadonlyArray<DeepPartial<U>> | |
: DeepPartial<T[P]> | |
}; | |
export type AssignmentAction = { type: 'ASSIGNMENT', payload: DeepPartial<State> } | |
export class Path<S> { | |
state: S; | |
breadcrumbs: String[]; | |
constructor(state: S, breadcrumbs: String[] = []) { | |
this.state = state; | |
this.breadcrumbs = breadcrumbs; | |
} | |
path<K extends keyof S>(key: K): Path<S[K]> { | |
const next = this.state[key] | |
return new Path<typeof next>(next, this.breadcrumbs.concat([key as string])); | |
} | |
value(): S { | |
return this.state; | |
} | |
action(assignment: S): AssignmentAction { | |
const leaf: any = { [this.breadcrumbs[this.breadcrumbs.length - 1] as string]: assignment }; | |
const keyTree = this.breadcrumbs.reverse().slice(1).reduce((acc, next) => { | |
return { [next as string]: acc }; | |
}, leaf); | |
return { | |
type: 'ASSIGNMENT', | |
payload: keyTree | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment