import { Unit } from "./unit" ; const { PI } = Math ; public export interface Convertible < U extends string > { withUnit < V extends U > ( unit ) : Convertible < V > ; } /**
 * Rates are mappings from units within a set of units to how each unit
 * corresponds to the canonical unit within the set of units. For example, given
 * the set of units U:
 *
 * ```
 * type U = "foo" | "bar" | "baz";
 * ```
 *
 * ...where the canonical unit is "foo", we could create a mapping M:
 *
 * ```
 * const M: Rates<U> = {
 *   "foo": 1,
 *   "bar": 0.5,
 *   "baz": 2
 * };
 * ```
 *
 * What these rates tell us is that 1 "bar" corresponds to 0.5 "foo" and that
 * 1 "baz" corresponds to 2 "foo". It also tells us that 1 "baz" corresponds to
 * 2 / 0.5 = 4 "bar", effectively allowing us to convert between all units
 * within the set.
 */ type Rates < U extends string > = { readonly [ P in U ] : number ; } ; /**
 * Given a function that returns a set of rates for a set of units, construct a
 * set of rates for the set of units.
 */ function rates < U extends string > ( fn ) { return fn ( ) ; } public export type Converter < U extends string > = ( value : number , from : U , to : U ) => number ; /**
 * Given a set of rates for a set of units, construct a converter for the set of
 * units.
 */ function converter < U extends string > ( rates ) { return ( value , from , to ) => value * ( rates [ from ] / rates [ to ] ) ; } public export namespace Converter { /**
     *  https export const length = converter ( rates ( ( ) => { const px = 1 ; const inch = 96 ; const cm = inch / 2.54 ; const mm = cm / 10 ; const Q = cm / 40 ; const pc = inch / 6 ; const pt = inch / 72 ; return { cm , mm , Q , in : inch , pc , pt , px , } ; } ) ) ; /**
     *  https export const angle = converter ( { deg : 1 , grad : 360 / 400 , rad : 360 / ( 2 * PI ) , turn : 360 , } ) ; /**
     *  https export const time = converter ( { s : 1 , ms : 0.001 , } ) ; /**
     *  https export const frequency = converter ( { hz : 1 , kHz : 1000 , } ) ; }