Skip to main content
Univerto uses a fluent API design pattern that enables you to chain method calls together for readable and intuitive unit conversions.

What is a Fluent API?

A fluent API is a design pattern that allows you to chain methods together in a natural, readable way. Instead of nesting function calls or using multiple statements, you create a flowing sequence that reads almost like a sentence.

Method Chaining Pattern

Every Univerto conversion follows the same three-step pattern:
from(value, sourceUnit) → to(targetUnit) → convert()

Step 1: from(value, unit)

Specify the starting value and its unit:
import { TIME_UNIT, TimeUnitConverter } from 'univerto/time'

TimeUnitConverter.from(1, TIME_UNIT.HOUR)
This returns an object with a to() method, enforcing the correct order of operations.

Step 2: to(unit)

Specify the target unit for conversion:
TimeUnitConverter.from(1, TIME_UNIT.HOUR)
  .to(TIME_UNIT.MILLISECOND)
This returns an object with conversion methods: convert(), convertToFraction(), and convertToRational().

Step 3: Choose Your Result Format

You have three options for getting the result:

convert() - Standard Number Result

const milliseconds = TimeUnitConverter.from(1, TIME_UNIT.HOUR)
  .to(TIME_UNIT.MILLISECOND)
  .convert()

console.log(milliseconds) // 3600000

convertToFraction() - Fraction Object

const fraction = TimeUnitConverter.from(1, TIME_UNIT.HOUR)
  .to(TIME_UNIT.MILLISECOND)
  .convertToFraction()

console.log(fraction) // { numerator: 3600000, denominator: 1 }

convertToRational() - Rational Instance

const rational = TimeUnitConverter.from(1, TIME_UNIT.HOUR)
  .to(TIME_UNIT.MILLISECOND)
  .convertToRational()

// Returns a Rational class instance with internal precision

Benefits of Fluent Design

Readability

The fluent API reads like natural language:
// Clear and self-documenting
LengthUnitConverter.from(5, LENGTH_UNIT.KILOMETER)
  .to(LENGTH_UNIT.METER)
  .convert()
Compare this to a non-fluent approach:
// Less intuitive
convert(5, LENGTH_UNIT.KILOMETER, LENGTH_UNIT.METER)

Type Safety

The chaining pattern enables TypeScript to provide autocomplete and type checking at each step:
import { MASS_UNIT, MassUnitConverter } from 'univerto/mass'

MassUnitConverter.from(100, MASS_UNIT.GRAM)
  .to(MASS_UNIT.KILOGRAM) // TypeScript knows valid units here
  .convert() // TypeScript knows available methods here

Discoverability

IDE autocomplete naturally guides you through the conversion process. After typing .from(), your IDE will suggest .to(). After .to(), it suggests the conversion methods.

Enforced Correctness

The API structure prevents invalid operations. You cannot call convert() without first specifying both source and target units:
// This won't compile - you must call to() first
TimeUnitConverter.from(1, TIME_UNIT.HOUR).convert() // ❌ Error

// Correct usage
TimeUnitConverter.from(1, TIME_UNIT.HOUR)
  .to(TIME_UNIT.SECOND)
  .convert() // ✓ Valid

Real-World Examples

Converting Data Sizes

import { DATA_UNIT, DataUnitConverter } from 'univerto/data'

const gigabytes = DataUnitConverter.from(1024, DATA_UNIT.MEGABYTE)
  .to(DATA_UNIT.GIGABYTE)
  .convert()

console.log(gigabytes) // 1

Converting Speeds

import { SPEED_UNIT, SpeedUnitConverter } from 'univerto/speed'

const mph = SpeedUnitConverter.from(100, SPEED_UNIT.KILOMETER_PER_HOUR)
  .to(SPEED_UNIT.MILE_PER_HOUR)
  .convert()

console.log(mph) // ~62.137

Converting Volumes

import { VOLUME_UNIT, VolumeUnitConverter } from 'univerto/volume'

const liters = VolumeUnitConverter.from(1, VOLUME_UNIT.GALLON)
  .to(VOLUME_UNIT.LITER)
  .convert()

console.log(liters) // ~3.785

Implementation Details

The fluent API is implemented using nested functions that return objects with specific methods. Here’s how the pattern works internally:
function from(fromQuantity: number, fromUnit: Unit) {
  return {
    to(targetUnit: Unit) {
      return {
        convert() { /* conversion logic */ },
        convertToFraction() { /* fraction logic */ },
        convertToRational() { /* rational logic */ }
      }
    }
  }
}
This structure is generated by the createPreciseConverter function found in ~/workspace/source/src/features/core/utils/create-precise-converter/index.ts:3-47. Each returned object exposes only the methods that make sense at that point in the chain, guiding you toward a complete conversion.

Build docs developers (and LLMs) love