Skip to content

Type System ​

Complete reference for TypeScript types and interfaces in the Route Optimization Map library.

Overview ​

All packages are written in TypeScript and provide comprehensive type definitions. This guide covers the core types used across the library.

Core Types ​

LatLng ​

Geographic coordinates (latitude and longitude).

typescript
interface LatLng {
  lat: number; // Latitude: -90 to 90
  lng: number; // Longitude: -180 to 180
}

Example:

typescript
const bangkok: LatLng = {
  lat: 13.7563,
  lng: 100.5018,
};

Stop ​

A single location on a route.

typescript
interface Stop {
  id: string;
  location: LatLng;
  name?: string;
  address?: string;
  duration?: number;
  metadata?: Record<string, any>;
}

Example:

typescript
const deliveryStop: Stop = {
  id: 'delivery-001',
  location: { lat: 13.7563, lng: 100.5018 },
  name: 'Customer A',
  address: '123 Sukhumvit Road',
  duration: 15, // minutes
  metadata: {
    orderId: 'ORD-12345',
    priority: 'high',
  },
};

Route ​

A sequence of stops to visit.

typescript
interface Route {
  stops: Stop[];
  options?: RouteOptions;
}

Example:

typescript
const deliveryRoute: Route = {
  stops: [
    { id: '1', location: { lat: 13.7563, lng: 100.5018 } },
    { id: '2', location: { lat: 13.7467, lng: 100.5352 } },
  ],
  options: {
    polylineOptions: {
      strokeColor: '#FF0000',
      strokeWeight: 6,
    },
  },
};

RouteOptions ​

Customization options for route rendering.

typescript
interface RouteOptions {
  polylineOptions?: PolylineOptions;
  markerOptions?: MarkerOptions;
  fitBounds?: boolean;
}

interface PolylineOptions {
  strokeColor?: string;
  strokeOpacity?: number;
  strokeWeight?: number;
  geodesic?: boolean;
}

interface MarkerOptions {
  showLabels?: boolean;
  labelColor?: string;
  startMarker?: MarkerConfig;
  endMarker?: MarkerConfig;
  stopMarker?: MarkerConfig;
}

interface MarkerConfig {
  icon?: string | MarkerIcon;
  label?: string | MarkerLabel;
}

Example:

typescript
const options: RouteOptions = {
  polylineOptions: {
    strokeColor: '#4CAF50',
    strokeOpacity: 0.8,
    strokeWeight: 5,
    geodesic: true,
  },
  markerOptions: {
    showLabels: true,
    labelColor: '#FFFFFF',
    startMarker: {
      icon: '/icons/start.png',
      label: 'START',
    },
  },
  fitBounds: true,
};

Map Types ​

MapConfig ​

Configuration for map initialization.

typescript
interface MapConfig {
  apiKey: string;
  center?: LatLng;
  zoom?: number;
  mapTypeId?: 'roadmap' | 'satellite' | 'hybrid' | 'terrain';
  styles?: MapStyle[];
  restriction?: MapRestriction;
  gestureHandling?: 'cooperative' | 'greedy' | 'none' | 'auto';
}

Example:

typescript
const mapConfig: MapConfig = {
  apiKey: 'YOUR_API_KEY',
  center: { lat: 13.7563, lng: 100.5018 },
  zoom: 12,
  mapTypeId: 'roadmap',
  gestureHandling: 'cooperative',
};

MapBounds ​

Geographic boundaries.

typescript
interface MapBounds {
  north: number;
  south: number;
  east: number;
  west: number;
}

Example:

typescript
const thailandBounds: MapBounds = {
  north: 20.5,
  south: 5.5,
  east: 106.0,
  west: 97.0,
};

Optimization Types ​

OptimizationRequest ​

Request for route optimization.

typescript
interface OptimizationRequest {
  shipments: Shipment[];
  vehicles: OptimizationVehicle[];
  globalStartTime?: string;
  globalEndTime?: string;
  searchMode?: 'RETURN_FAST' | 'CONSUME_ALL_AVAILABLE_TIME';
}

interface Shipment {
  id: string;
  pickupLocation?: OptimizationLocation | OptimizationLocation[];
  deliveryLocation?: OptimizationLocation | OptimizationLocation[];
  loadDemands?: Record<string, number>;
  pickupTimeWindows?: TimeWindow[];
  deliveryTimeWindows?: TimeWindow[];
}

interface OptimizationLocation {
  latitude: number;
  longitude: number;
}

interface OptimizationVehicle {
  id: string;
  startLocation?: OptimizationLocation;
  endLocation?: OptimizationLocation;
  loadLimits?: LoadLimit[];
  costPerKilometer?: number;
  costPerHour?: number;
  travelMode?: 'DRIVING' | 'WALKING' | 'BICYCLING';
}

interface TimeWindow {
  startTime: string; // ISO 8601 format
  endTime: string;
}

interface LoadLimit {
  type: string;
  maxLoad?: number;
  softMaxLoad?: number;
  costPerUnitAboveSoftMax?: number;
}

Example:

typescript
const optimizationRequest: OptimizationRequest = {
  shipments: [
    {
      id: 'shipment-1',
      deliveryLocation: {
        latitude: 13.7563,
        longitude: 100.5018,
      },
      loadDemands: { weight: 50 },
      deliveryTimeWindows: [
        {
          startTime: '2025-12-12T09:00:00Z',
          endTime: '2025-12-12T17:00:00Z',
        },
      ],
    },
  ],
  vehicles: [
    {
      id: 'vehicle-1',
      startLocation: {
        latitude: 13.7563,
        longitude: 100.5018,
      },
      loadLimits: [
        {
          type: 'weight',
          maxLoad: 1000,
        },
      ],
      travelMode: 'DRIVING',
    },
  ],
  searchMode: 'RETURN_FAST',
};

OptimizationResponse ​

Response from route optimization.

typescript
interface OptimizationResponse {
  success: boolean;
  routes?: OptimizedRoute[];
  metrics?: OptimizationMetrics;
  statistics?: OptimizationStatistics;
  error?: string;
}

interface OptimizedRoute {
  vehicleId: string;
  stops?: OptimizedStop[];
  metrics?: RouteMetrics;
}

interface OptimizedStop {
  shipmentId?: string;
  location?: OptimizationLocation;
  arrivalTime?: string;
  departureTime?: string;
  loadAfterStop?: Record<string, number>;
}

interface OptimizationMetrics {
  totalDistance?: number;
  totalDuration?: number;
  totalCost?: number;
}

interface OptimizationStatistics {
  usedVehicleCount: number;
  earliestVehicleStartTime?: string;
  latestVehicleEndTime?: string;
}

Example:

typescript
const response: OptimizationResponse = {
  success: true,
  routes: [
    {
      vehicleId: 'vehicle-1',
      stops: [
        {
          shipmentId: 'shipment-1',
          location: { latitude: 13.7563, longitude: 100.5018 },
          arrivalTime: '2025-12-12T09:30:00Z',
          departureTime: '2025-12-12T09:45:00Z',
        },
      ],
      metrics: {
        distance: 15.5,
        duration: 1800,
      },
    },
  ],
  metrics: {
    totalDistance: 15.5,
    totalDuration: 1800,
    totalCost: 250,
  },
};

Framework-Specific Types ​

React Types ​

typescript
// useRouteMap
interface UseRouteMapOptions extends MapConfig {
  onError?: (error: Error) => void;
}

interface UseRouteMapReturn {
  mapRef: RefObject<HTMLDivElement>;
  map: google.maps.Map | null;
  isReady: boolean;
  renderRoute: (route: Route) => void;
  clearRoute: () => void;
  addMarker: (location: LatLng, options?: MarkerOptions) => void;
  removeMarker: (id: string) => void;
  clearMarkers: () => void;
}

// useMapControls
interface UseMapControlsReturn {
  center: LatLng | null;
  zoom: number | null;
  bounds: MapBounds | null;
  setCenter: (location: LatLng) => void;
  setZoom: (zoom: number) => void;
  fitBounds: (bounds: MapBounds) => void;
}

// useRouteOptimization
interface UseRouteOptimizationResult {
  status: OptimizationStatus;
  data: OptimizationResponse | null;
  error: string | null;
  isLoading: boolean;
  isSuccess: boolean;
  isError: boolean;
  optimize: (request: OptimizationRequest) => Promise<OptimizationResponse>;
  reset: () => void;
  reinitialize: (config: RouteCalculatorConfig) => Promise<void>;
}

type OptimizationStatus = 'idle' | 'initializing' | 'optimizing' | 'success' | 'error';

Vue Types ​

typescript
// useRouteMap
interface UseRouteMapOptions extends MapConfig {
  mapElement: Ref<HTMLDivElement | undefined>;
  onError?: (error: Error) => void;
}

interface UseRouteMapReturn {
  map: Ref<google.maps.Map | null>;
  isReady: Ref<boolean>;
  renderRoute: (route: Route) => void;
  clearRoute: () => void;
  addMarker: (location: LatLng, options?: MarkerOptions) => void;
  removeMarker: (id: string) => void;
  clearMarkers: () => void;
}

// useMapControls
interface UseMapControlsReturn {
  center: Ref<LatLng | null>;
  zoom: Ref<number | null>;
  bounds: Ref<MapBounds | null>;
  setCenter: (location: LatLng) => void;
  setZoom: (zoom: number) => void;
  fitBounds: (bounds: MapBounds) => void;
}

// useRouteOptimization
interface UseRouteOptimizationResult {
  status: Ref<OptimizationStatus>;
  data: Ref<OptimizationResponse | null>;
  error: Ref<string | null>;
  isLoading: Readonly<Ref<boolean>>;
  isSuccess: Readonly<Ref<boolean>>;
  isError: Readonly<Ref<boolean>>;
  optimize: (request: OptimizationRequest) => Promise<OptimizationResponse>;
  reset: () => void;
  reinitialize: (config: RouteCalculatorConfig) => Promise<void>;
}

Vanilla Types ​

typescript
// RouteMap
interface RouteMapConfig extends MapConfig {
  onError?: (error: Error) => void;
}

class RouteMap {
  constructor(config: RouteMapConfig);
  initialize(element: HTMLElement): Promise<void>;
  destroy(): void;

  isReady(): boolean;
  getMap(): google.maps.Map | null;
  getCurrentRoute(): Route | null;

  renderRoute(route: Route): void;
  clearRoute(): void;

  setCenter(location: LatLng): void;
  getCenter(): LatLng | null;

  setZoom(zoom: number): void;
  getZoom(): number | null;

  fitBounds(bounds: MapBounds): void;
  getBounds(): MapBounds | null;

  addMarker(location: LatLng, options?: MarkerOptions): void;
  removeMarker(id: string): void;
  clearMarkers(): void;
}

// RouteOptimizer
interface RouteOptimizerEvents {
  'status-change': OptimizationStatus;
  progress: { progress: number; step: string };
  success: OptimizationResponse;
  error: Error;
  start: void;
  reset: void;
}

class RouteOptimizer {
  constructor(config: RouteCalculatorConfig);

  get status(): OptimizationStatus;
  get data(): OptimizationResponse | null;
  get error(): Error | null;
  get isLoading(): boolean;
  get isSuccess(): boolean;
  get isError(): boolean;

  initialize(): Promise<void>;
  optimize(request: OptimizationRequest): Promise<OptimizationResponse>;
  updateProgress(progress: number, step?: string): void;
  reset(): void;
  reinitialize(config: RouteCalculatorConfig): Promise<void>;
  destroy(): void;

  on<K extends keyof RouteOptimizerEvents>(
    event: K,
    listener: (data: RouteOptimizerEvents[K]) => void
  ): void;

  off<K extends keyof RouteOptimizerEvents>(
    event: K,
    listener: (data: RouteOptimizerEvents[K]) => void
  ): void;
}

Type Guards ​

Utility functions for type checking:

typescript
// Check if location is valid
function isValidLatLng(location: any): location is LatLng {
  return (
    typeof location === 'object' &&
    typeof location.lat === 'number' &&
    typeof location.lng === 'number' &&
    location.lat >= -90 &&
    location.lat <= 90 &&
    location.lng >= -180 &&
    location.lng <= 180
  );
}

// Check if stop is valid
function isValidStop(stop: any): stop is Stop {
  return typeof stop === 'object' && typeof stop.id === 'string' && isValidLatLng(stop.location);
}

// Check if route is valid
function isValidRoute(route: any): route is Route {
  return (
    typeof route === 'object' &&
    Array.isArray(route.stops) &&
    route.stops.length >= 2 &&
    route.stops.every(isValidStop)
  );
}

Usage:

typescript
function processRoute(data: unknown) {
  if (isValidRoute(data)) {
    // TypeScript knows data is Route
    routeMap.renderRoute(data);
  } else {
    console.error('Invalid route data');
  }
}

Generic Types ​

For advanced type safety:

typescript
// Generic Stop with custom metadata
interface Stop<T = Record<string, any>> {
  id: string;
  location: LatLng;
  name?: string;
  address?: string;
  duration?: number;
  metadata?: T;
}

// Usage
interface DeliveryMetadata {
  orderId: string;
  customerId: string;
  packageWeight: number;
  priority: 'low' | 'medium' | 'high';
}

const deliveryStop: Stop<DeliveryMetadata> = {
  id: 'delivery-001',
  location: { lat: 13.7563, lng: 100.5018 },
  metadata: {
    orderId: 'ORD-12345',
    customerId: 'CUST-001',
    packageWeight: 5.5,
    priority: 'high',
  },
};

Utility Types ​

typescript
// Partial route for updates
type PartialRoute = Partial<Route> & {
  stops: Stop[];
};

// Read-only route
type ReadonlyRoute = Readonly<Route> & {
  readonly stops: readonly Readonly<Stop>[];
};

// Pick specific stop properties
type StopLocation = Pick<Stop, 'id' | 'location'>;

// Omit metadata
type BasicStop = Omit<Stop, 'metadata'>;

// Required properties
type RequiredStop = Required<Stop>;

Type Imports ​

Import types from packages:

typescript
// From Core
import type {
  LatLng,
  Stop,
  Route,
  RouteOptions,
  MapConfig,
  MapBounds,
  OptimizationRequest,
  OptimizationResponse,
} from '@route-optimization/core';

// From React
import type {
  UseRouteMapOptions,
  UseRouteMapReturn,
  UseMapControlsReturn,
  UseRouteOptimizationResult,
} from '@route-optimization/react';

// From Vue
import type {
  UseRouteMapOptions,
  UseRouteMapReturn,
  UseMapControlsReturn,
  UseRouteOptimizationResult,
} from '@route-optimization/vue';

// From Vanilla
import type {
  RouteMapConfig,
  OptimizationStatus,
  RouteOptimizerEvents,
} from '@route-optimization/vanilla';

Best Practices ​

1. Use Strict Types ​

Enable strict TypeScript options:

json
// tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "strictNullChecks": true,
    "noImplicitAny": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true
  }
}

2. Type Assertions ​

Use type guards instead of assertions:

typescript
// ✅ Good - Type guard
if (isValidRoute(data)) {
  processRoute(data);
}

// ❌ Avoid - Type assertion
processRoute(data as Route);

3. Const Assertions ​

Use const assertions for literal types:

typescript
const mapConfig = {
  apiKey: 'YOUR_API_KEY',
  mapTypeId: 'roadmap',
  zoom: 12,
} as const;

4. Generic Constraints ​

Constrain generic types appropriately:

typescript
function getStopMetadata<T extends Record<string, any>>(
  stop: Stop<T>,
  key: keyof T
): T[keyof T] | undefined {
  return stop.metadata?.[key];
}

Next Steps ​

Released under the MIT License.