/** Serializable representation of a ratio. */ export type RatioData = [numerator: number, denominator: number]; /** Representation of a ratio for performing fractional artithmetic. */ export default class Ratio { private readonly _numerator: number; private readonly _denominator: number; get numerator(): number { return this._numerator; } get denominator(): number { return this._denominator; } constructor(numerator: number, denominator: number) { if (!Number.isInteger(numerator) || !Number.isInteger(denominator)) { throw new TypeError( `Ratio must have integer parts: ${numerator} / ${denominator}`, ); } if (denominator === 0) { throw new RangeError("Ratio demnominator cannot be zero"); } this._numerator = numerator; this._denominator = denominator; } multiplyRatio(other: Ratio): Ratio { return new Ratio( this.numerator * other.numerator, this.denominator * other.denominator, ); } divideRatio(other: Ratio): Ratio { return new Ratio( this.numerator * other.denominator, this.denominator * other.numerator, ); } toNumber(): number { return this.numerator / this.denominator; } static fromInteger(n: number): Ratio { return new Ratio(n, 1); } toData(): RatioData { return [this.numerator, this.denominator]; } static fromData(ratio: RatioData): Ratio { return new Ratio(ratio[0], ratio[1]); } }