UNPKG

@fractorysolutions/safe-units

Version:
189 lines (188 loc) 8.63 kB
import { AllowedExponents, DivideUnits, DivisorUnit, ExponentiateUnit, MultiplicandUnit, MultiplyUnits, Unit, UnitWithSymbols } from "./unitTypeArithmetic"; export interface MeasureFormatter<N> { formatValue?: (value: N) => string; formatUnit?: (unit: UnitWithSymbols) => string; } /** The set of numeric operations required to fully represent a `GenericMeasure` for a given numeric type */ export interface NumericOperations<N> { /** Returns the multiplicative identity for numbers of type N */ one(): N; /** Returns the negative of a number of type N */ neg(value: N): N; /** Returns the sum of two numbers of type N */ add(left: N, right: N): N; /** Returns the difference of two numbers of type N */ sub(left: N, right: N): N; /** Returns the product of two numbers of type N */ mult(left: N, right: N): N; /** Returns the quotient of two numbers of type N */ div(left: N, right: N): N; /** Returns the base raised to the exponent for numbers of type N */ pow(base: N, exponent: number): N; /** Compares two numbers returning a negative, zero, or positive value. */ compare(left: N, right: N): number; /** Formats a number for display */ format(value: N): string; } /** A numeric value with a corresponding unit of measurement. */ export interface GenericMeasure<N, U extends Unit> { /** The numeric value of this measure */ readonly value: N; /** The unit of this measure */ readonly unit: UnitWithSymbols<U>; /** The symbol of the unit this measure represents (e.g. 0.3048 m = 1 ft) */ readonly symbol: string | undefined; /** * If this measure can be squared, squares it. If this measure is not squarable (due to exponent limitations), then * this function will have type `never`. * @returns this measure multiplied by itself */ squared: "2" extends AllowedExponents<U> ? () => GenericMeasure<N, ExponentiateUnit<U, "2">> : never; /** * If this measure can be cubed, cubes it. If this measure cannot be cubed (due to exponent limitations), then * this function will have type `never`. * @returns this cube of this measure */ cubed: "3" extends AllowedExponents<U> ? () => GenericMeasure<N, ExponentiateUnit<U, "3">> : never; /** * Raises this measure to a given power. If the result would give exponents outside of the allowable bounds, this * will return `never`. * @param exponent the exponent to raise this measure to * @returns this exponent to the given power */ toThe<E extends AllowedExponents<U>>(exponent: E): GenericMeasure<N, ExponentiateUnit<U, E>>; /** * Adds this measure to another measure with the same unit. * @param other the value to add * @returns the sum */ plus(other: GenericMeasure<N, U>): GenericMeasure<N, U>; /** * Subtracts another measure with the same unit from this measure. * @param other the value to subtract * @returns the difference */ minus(other: GenericMeasure<N, U>): GenericMeasure<N, U>; /** * Negates the value of this measure. * @returns A measure whose value is the negative of this measure */ negate(): GenericMeasure<N, U>; /** * Multiplies this measure by a dimensionless value. * @param value a scalar dimensionless value by which to scale this measure * @returns A measure scaled by the value */ scale(value: N): GenericMeasure<N, U>; /** * Multiplies this measure with another measure. * @param other the value to multiply * @returns the product measure with a unit thats the product of the units */ times<V extends MultiplicandUnit<U>>(other: GenericMeasure<N, V>): GenericMeasure<N, MultiplyUnits<U, V>>; /** * Divides this measure by another measure. * @param other the divisor * @returns the quotient measure with a unit thats the quotient of the units */ over<V extends DivisorUnit<U>>(other: GenericMeasure<N, V>): GenericMeasure<N, DivideUnits<U, V>>; /** * Divides this measure by another measure. * @param other the divisor * @returns the quotient measure with a unit thats the quotient of the units */ per<V extends DivisorUnit<U>>(other: GenericMeasure<N, V>): GenericMeasure<N, DivideUnits<U, V>>; /** * Divides this measure by another measure. * @param other the divisor * @returns the quotient measure with a unit thats the quotient of the units */ div<V extends DivisorUnit<U>>(other: GenericMeasure<N, V>): GenericMeasure<N, DivideUnits<U, V>>; /** * Returns the reciprocal of this measure. * @returns the reciprocal of this measure with a recriprocal unit */ inverse(): GenericMeasure<N, ExponentiateUnit<U, "-1">>; /** * Returns the reciprocal of this measure. * @returns the reciprocal of this measure with a recriprocal unit */ reciprocal(): GenericMeasure<N, ExponentiateUnit<U, "-1">>; /** * Maps the value and possibly unit of this measure. * @param valueMap a mapping on the value of the measure * @param unitMap an optional mapping on the unit of the measure * @returns a new measure whose value and unit have been mapped */ unsafeMap(fn: (value: N) => N): GenericMeasure<N, U>; unsafeMap<V extends Unit>(valueMap: (value: N) => N, unitMap: (unit: UnitWithSymbols<U>) => UnitWithSymbols<V>): GenericMeasure<N, V>; /** * Compares two measures to each other. Returns a negative value if this < other, a postive value if this > other * and 0 if the two are equal. * @param another measure with the same unit * @returns a value indicating how the value of this measure compares to the value of the other measure */ compare(other: GenericMeasure<N, U>): number; /** * @param another measure with the same unit * @returns true if the value of this measure is less than the value of the other measure */ lt(other: GenericMeasure<N, U>): boolean; /** * @param another measure with the same unit * @returns true if the value of this measure is less than or equal to the value of the other measure */ lte(other: GenericMeasure<N, U>): boolean; /** * @param another measure with the same unit * @returns true if the value of this measure is equal to the value of the other measure */ eq(other: GenericMeasure<N, U>): boolean; /** * @param another measure with the same unit * @returns true if the value of this measure is not equal to the value of the other measure */ neq(other: GenericMeasure<N, U>): boolean; /** * @param another measure with the same unit * @returns true if the value of this measure is greater than or equal to the value of the other measure */ gte(other: GenericMeasure<N, U>): boolean; /** * @param another measure with the same unit * @returns true if the value of this measure is greater than the value of the other measure */ gt(other: GenericMeasure<N, U>): boolean; /** * Formats the value and the unit. * @returns a string representation of measure */ toString(formatter?: MeasureFormatter<N>): string; /** * Formats this measure as a product of another unit. If the given unit has a symbol, this will format as a number * followed by that symbol. If not, this is equivalent to calling `toString()`. * @param a unit to be used to represent this measure * @returns a string representation of measure */ in(unit: GenericMeasure<N, U>, formatter?: MeasureFormatter<N>): string; /** * Converts this measure to another unit, e.g. for passing to an external API that requires pure numbers of particular unit. * @param unit the unit to convert to * @returns the numeric value of this measure in the given unit */ valueIn(unit: GenericMeasure<N, U>): N; /** * Adds a symbol to this measure. * @param symbol the symbol of the unit represented by this measure */ withSymbol(symbol: string | undefined): GenericMeasure<N, U>; /** Shallow copies this measure instance. */ clone(): GenericMeasure<N, U>; } /** * Translates a measure type from one numeric type to another while preserving the unit. * @example * const metersPerSecond = meters.per(seconds); * type Velocity<N> = LiftMeasure<typeof metersPerSecond, N>; */ export type LiftMeasure<M extends GenericMeasure<any, any>, N> = M extends GenericMeasure<any, infer U> ? GenericMeasure<N, U> : never;