Skip to content

Instantly share code, notes, and snippets.

@JasonKleban
Created June 5, 2017 18:16
Show Gist options
  • Save JasonKleban/1387f8b6caef083bdd10419028485006 to your computer and use it in GitHub Desktop.
Save JasonKleban/1387f8b6caef083bdd10419028485006 to your computer and use it in GitHub Desktop.
Typescript Functional Lens
interface MyStructure {
a: boolean;
b: number;
c: string;
d: {
e: boolean;
f: number;
g: string[];
}
}
type Lensed<R, T> = {
<M extends keyof T>(member: M) : Lensed<R, T[M]>
read(root: R): T
write(root: R, value: T): R
}
function Lens<R>() : Lensed<R, R> {
function makeLens<R, P, M extends keyof P>(parent : ((root : R) => P), selfMember : M) : Lensed<R, P[M]> {
let lens: any = <N extends keyof P[M]>(member: N): Lensed<R, P[M][N]> => {
let selfAccessor = (root: R) => parent(root)[selfMember];
return makeLens(selfAccessor, member);
};
lens.read = (root: R): P[M] => parent(root)[selfMember];
lens.write = (root: R, value: P[M]): R => {
let newRoot = JSON.parse(JSON.stringify(root));
parent(newRoot)[selfMember] = value;
return Object.freeze(newRoot);
}
return <Lensed<R, P[M]>>lens;
}
let rootLens: any = <M extends keyof R>(member: M): Lensed<R, R[M]> => makeLens<R, R, M>(root => root, member);
rootLens.read = (root: R): R => root;
rootLens.write = (value: R): R => value;
return rootLens;
}
var lens = Lens<MyStructure>();
var test: MyStructure = {
a: false,
b: 3,
c: 'Blah',
d: {
e: true,
f: 42,
g: []
}
};
lens.read(test);
lens.write(test, test);
var getted = lens('d')('f').read(test);
var setted = lens('d')('f').write(test, 5);
var setted2 = lens('d')('g').write(setted, ['', '']);
console.log(setted2);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment