Skip to content

Instantly share code, notes, and snippets.

@fvilante
Created May 20, 2019 13:58
Show Gist options
  • Save fvilante/97b8e61244ae1209088d3e2d4078d3ce to your computer and use it in GitHub Desktop.
Save fvilante/97b8e61244ae1209088d3e2d4078d3ce to your computer and use it in GitHub Desktop.
Static Lenses prove of concept in Typescript
// =======================================================================
// Lenses
// =======================================================================
type Setter<A, B extends keyof A> = Func2<A, A[B], A[B]>
type Getter<A, B extends keyof A> = Func<A, A[B]>
type Property<A, B extends keyof A> = B
type _Object<A> = A
type _NextType<A, B extends keyof A> = A[B]
interface LensState<A, B extends keyof A> {
_Object: _Object<A> // :: A
_NextObject: _NextType<A,B> // :: A[B]
Prop: Property<A,B> //:: B
Getter: Getter<A,B> // :: A -> A[B]
Setter: Setter<A,B> // :: A -> A[B]
}
class FirstPropSetter<A, B extends keyof A> {
constructor(private _State: LensState<A, B>) { }
// states
Prop = <K extends keyof A>(key: K): NextPropSetter<A, K> =>
new NextPropSetter({
_Object: this._State._Object,
_NextObject: this._State._Object[key],
Prop: key,
Getter: (_:A) => _[key],
Setter: (_:A, value: A[K]) => value
})
}
class NextPropSetter<A, B extends keyof A> {
constructor(private _State: LensState<A, B>) { }
// states
NextProp = <K extends keyof A[B]>(key: K): NextPropSetter<A[B], K> =>
new NextPropSetter({
_Object: this._State._NextObject,
_NextObject: this._State._NextObject[key],
Prop: key,
Getter: undefined,
Setter: undefined,
})
}
class Lens<A, B extends keyof A> {
// constructors
static Of = <T extends object>(o: T): FirstPropSetter<T, undefined> =>
new FirstPropSetter({
_Object: o,
_NextObject: undefined,
Prop: undefined,
Getter: undefined,
Setter: undefined,
})
}
interface Test {
a: string
b: number
c?: {
x: number
y: number
z: {
a: number,
b: number
}
}
}
const test: Test = {
a:'2',
b: 3
}
// Use (Static Lenses - from Above)
const L = (x: Test) => Lens.Of(x).Prop('c').NextProp('z').NextProp('a')
const L1 = (x: Test) => Lens.Of(x).Prop('a')
// Use (Dynamic Lenses - with pluck)
function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {
return names.map(n => o[n]);
}
const zzz = pluck(test, ['a','b','a'])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment