import { getExponentValue } from "../exponent/exponentValueArithmetic" ; import { defaultFormatUnit } from "./format" ; import { GenericMeasure , MeasureFormatter , NumericOperations } from "./genericMeasure" ; import { AllowedExponents , DivideUnits , DivisorUnit , ExponentiateUnit , MultiplicandUnit , MultiplyUnits , Unit , UnitWithSymbols , } from "./unitTypeArithmetic" ; import { divideUnits , exponentiateUnit , multiplyUnits } from "./unitValueArithmetic" ; type GenericMeasureConstructor < N > = new < U extends Unit > ( value , unit , symbol ? ) => GenericMeasure < N , U > ; export function createMeasureClass < N > ( num ) { function getFormatter ( formatter ) { if ( formatter === undefined ) { return { formatValue : num . format , formatUnit : defaultFormatUnit , } ; } else { return { formatValue : formatter . formatValue || num . format , formatUnit : formatter . formatUnit || defaultFormatUnit , } ; } } class Measure < U extends Unit > implements GenericMeasure < N , U > { public readonly symbol : string | undefined ; public squared ! : "2" extends AllowedExponents < U > ? ( ) => GenericMeasure < N , ExponentiateUnit < U , "2" > > : never ; public cubed ! : "3" extends AllowedExponents < U > ? ( ) => GenericMeasure < N , ExponentiateUnit < U , "3" > > : never ; constructor ( public readonly value , public readonly unit , symbol ? ) { this . symbol = symbol ; } public plus ( other ) { return new Measure ( num . add ( this . value , other . value ) , this . unit ) ; } public minus ( other ) { return new Measure ( num . sub ( this . value , other . value ) , this . unit ) ; } public negate ( ) { return new Measure ( num . neg ( this . value ) , this . unit ) ; } public scale ( value ) { return new Measure ( num . mult ( this . value , value ) , this . unit ) ; } public times < V extends MultiplicandUnit < U > > ( other ) { return new Measure < any > ( num . mult ( this . value , other . value ) , multiplyUnits ( this . unit , other . unit ) ) as any ; } public over < V extends DivisorUnit < U > > ( other ) { return new Measure < any > ( num . div ( this . value , other . value ) , divideUnits ( this . unit , other . unit ) ) as any ; } public per < V extends DivisorUnit < U > > ( other ) { return this . over ( other ) ; } public div < V extends DivisorUnit < U > > ( other ) { return this . over ( other ) ; } public toThe < E extends AllowedExponents < U > > ( power ) { return new Measure ( num . pow ( this . value , getExponentValue ( power ) ) , exponentiateUnit ( this . unit , power ) ) ; } public inverse ( ) { return this . toThe ( "-1" ) ; } public reciprocal ( ) { return this . toThe ( "-1" ) ; } public unsafeMap < V extends Unit > ( valueMap , unitMap ? ) { const newUnit = unitMap === undefined ? this . unit : unitMap ( this . unit ) ; return new Measure < V > ( valueMap ( this . value ) , ( newUnit as unknown ) as UnitWithSymbols < V > ) ; } public compare ( other ) { return num . compare ( this . value , other . value ) ; } public lt ( other ) { return this . compare ( other ) < 0 ; } public lte ( other ) { return this . compare ( other ) <= 0 ; } public eq ( other ) { return this . compare ( other ) === 0 ; } public neq ( other ) { return this . compare ( other ) !== 0 ; } public gte ( other ) { return this . compare ( other ) >= 0 ; } public gt ( other ) { return this . compare ( other ) > 0 ; } public toString ( formatter ? ) { const { formatValue , formatUnit } = getFormatter ( formatter ) ; return `${ formatValue ( this . value ) } ${ formatUnit ( this . unit ) }` . trimRight ( ) ; } public in ( unit , formatter ? ) { if ( unit . symbol === undefined ) { return this . toString ( formatter ) ; } const { formatValue } = getFormatter ( formatter ) ; const value = formatValue ( num . div ( this . value , unit . value ) ) ; return `${ value } ${ unit . symbol }` ; } public withSymbol ( symbol ) { return new Measure ( this . value , this . unit , symbol ) ; } public clone ( ) { return new Measure ( this . value , this . unit ) ; } } Measure . prototype . squared = function ( ) : any { return this . toThe ( "2" ) ; } ; Measure . prototype . cubed = function ( ) : any { return this . toThe ( "3" ) ; } ; return Measure ; }