@typed/lenses
Version:
Strongly-typed functional lenses
42 lines (35 loc) • 1.37 kB
text/typescript
import { Head, Tail } from '@typed/lambda'
import { Lens, LensInput, LensOutput } from './Lens'
import { PathLens } from './PathLens'
import { pipe2 } from './pipe2'
import { PropLens } from './PropLens'
export type PipeLenses<A extends Lenses> = A extends ReadonlyArray<PropLens<any>>
? PathLens<GetPropKeys<A>>
: GetPipedLenses<LensInput<Head<A>>, LensOutput<Head<A>>, Tail<A>>
export function pipe<A extends Lenses>(...lenses: A): PipeLenses<A> {
return lenses.reduce(pipe2, Lens.id()) as PipeLenses<A>
}
type GetPropKeys<A extends Lenses> = {
[K in keyof A]: A[K] extends PropLens<infer R> ? R : never
}
type Lenses = readonly [Lens<any, any>, Lens<any, any>, ...ReadonlyArray<Lens<any, any>>]
type GetPipedLenses<I, O, Lenses extends ReadonlyArray<Lens<any, any>>> = Lens<
I,
VerifyLensesAreValidAndGetOutput<O, Lenses>
>
type VerifyLensesAreValidAndGetOutput<O, A extends ReadonlyArray<Lens<any, any>>> = {
complete: O extends LensInput<Head<A>>
? LensOutput<Head<A>>
: {
error: 'Invalid Lens composition'
from: O
to: LensInput<Head<A>>
}
continue: O extends LensInput<Head<A>>
? VerifyLensesAreValidAndGetOutput<LensOutput<Head<A>>, Tail<A>>
: {
error: 'Invalid Lens composition'
from: O
to: LensInput<Head<A>>
}
}[Tail<A> extends [] ? 'complete' : 'continue']