Skip to content

TypeScript Quickstart

bash
npm install maplibre-gl
npm install -D @types/maplibre-gl  # bundled in maplibre-gl since v4

Typed init

ts
import maplibregl, { Map, MapOptions, StyleSpecification } from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';

const PUB_KEY = import.meta.env.VITE_MFD_PUB_KEY;

const opts: MapOptions = {
  container: 'map',
  style: `https://api.mapsfordevs.com/styles/standard.json?key=${PUB_KEY}`,
  center: [28.04, -26.20],
  zoom: 11
};
const map: Map = new maplibregl.Map(opts);

API response types

ts
export interface MFDError { ok: false; error: string; code: string }
export interface MFDOk<T> { ok: true; data: T }
export type MFDResponse<T> = MFDOk<T> | MFDError;

export interface GeocodeItem {
  lat: number;
  lng: number;
  label: string;
  components: Record<string, string>;
  confidence: number;
  type: 'house' | 'street' | 'suburb' | 'city' | 'country';
}

export async function geocode(query: string, key: string): Promise<GeocodeItem[]> {
  const r = await fetch(
    `https://api.mapsfordevs.com/geocode/forward?q=${encodeURIComponent(query)}&limit=5`,
    { headers: { Authorization: `Bearer ${key}` } }
  );
  const body: MFDResponse<{ items: GeocodeItem[] }> = await r.json();
  if (!body.ok) throw new Error(body.error);
  return body.data.items;
}

Locale-switch helper, fully typed

ts
const TEXT_LAYERS = ['place_label', 'transportation_name', 'poi_label'] as const;

export function setMapLanguage(map: maplibregl.Map, lang: string): void {
  for (const layer of TEXT_LAYERS) {
    map.setLayoutProperty(layer, 'text-field', [
      'coalesce',
      ['get', `name:${lang}`],
      ['get', 'name:latin'],
      ['get', 'name']
    ]);
  }
}

Strict null safety

ts
const map: Map | null = ref<Map | null>(null);
if (!map) throw new Error('map not initialised');
map.flyTo({ center: [28, -26], zoom: 12 });