Skip to Content
TypeScript types

TypeScript types

@mapvx/web-components-ssr ships TypeScript declarations for the data exchanged between your page and <mapvx-website>: the userAction event payload, the initial-data shape and the maps SDK data models they refer to. Everything you can use from them is a type, so import it with import type. The declarations do not describe the element itself; Element typing shows what to add to your project.

import type { InitialData, UserAction } from '@mapvx/web-components-ssr'

Importing types

The declarations are part of the npm package; there is no separate @types package. Install the exact version you tested (see npm):

npm install --save-exact @mapvx/web-components-ssr@1.6.1
  • Entry: the package’s types field points to dist/types/public-api.d.ts. It is a single file with no imports, so TypeScript needs no other package to resolve it.
  • Import path: always the package root, '@mapvx/web-components-ssr', with import type. It resolves with moduleResolution set to bundler, node16 or nodenext, and with node10, which TypeScript 6.0 deprecates (there it requires "ignoreDeprecations": "6.0").
  • DOM library: the file references a DOM type (GeolocationPosition). In a tsconfig.json without the DOM library, such as one for server-only code, TypeScript reports Cannot find name 'GeolocationPosition' inside the file. Add "DOM" to lib or enable skipLibCheck.
  • Plain JavaScript: to get the types in an editor that checks JavaScript, reference them from JSDoc. JSDoc imports are comments, so they never load the bundle.
/** @typedef {import('@mapvx/web-components-ssr').UserAction} UserAction */

What the file exports:

GroupExportsDetails
Event payloadsUserAction, SelectFilterAction, ShowPlaceAction, SelectDestinationAction, SearchAction, ReturnToHomeActionUserAction
Initial dataInitialData, PlaceResponse, InstitutionResponseInitialData
Component modelsAnimationState, CategoryFiltersData, CurrentLocation, FormattedSchedule, RoutePoint, SearchDataOther models
Maps SDK data typesMVXPlace, Institution, Banner, MVXRoute, MVXRouteLeg, MVXRouteStep, MVXTransport, MVXLocation, CityFilterOption, OpeningHours, OpeningTime, DaysOfTheWeek, LatLng, InnerFloor, PropertyMaps SDK types
Declared values, not importableEMPTY_SEARCH_DATA, FALLBACK_IMAGE_URL, MEASUREMENT_ID, extractBannerColor, getSchedule, isCurrentLocation, isDealOrEventBanner, isPlace, prepareAllSchedules, toCurrentLocationTypes only

Types only

The package’s runtime entry (main) is dist/browser/main.js, the component bundle. Loading it registers <mapvx-website>; it is not a library. Its only exports are internal names that its own lazy chunks import, so none of the names in the declaration file can be imported at runtime.

The declaration file still declares some runtime values: the constants and functions in the last row of the table above, the AnimationState enum and the SDK classes (MVXPlace, Institution, Banner, MVXRoute, MVXRouteLeg, MVXRouteStep, MVXTransport). TypeScript accepts a value import of any of them, but the import fails afterwards:

  • A bundler stops the build because main.js has no such export. esbuild, for example, reports No matching export in "node_modules/@mapvx/web-components-ssr/dist/browser/main.js" for import "isPlace".
  • A browser that loads the module natively throws a SyntaxError because the module does not provide the requested export.
  • Any import of '@mapvx/web-components-ssr' that remains in the compiled output loads main.js, which registers the element. In server code it throws ReferenceError: HTMLElement is not defined (see Troubleshooting).

Names imported with import type can only be used as types. new MVXPlace(...), value instanceof MVXPlace and AnimationState.Playing do not compile (TS1361: ... cannot be used as a value because it was imported using 'import type'). What the component gives you, such as event.detail, is plain data, so no constructor is needed.

Write import type, not an inline type modifier:

// Do: removed completely from the compiled output import type { UserAction } from '@mapvx/web-components-ssr' // Avoid: with verbatimModuleSyntax this compiles to // import {} from '@mapvx/web-components-ssr' import { type UserAction } from '@mapvx/web-components-ssr'

With verbatimModuleSyntax enabled, when every specifier of an import has an inline type modifier, TypeScript keeps it as an empty import, and an empty import still loads the bundle.

To load the component, import the package only for its side effect in browser-only code (import '@mapvx/web-components-ssr') or use a <script type="module"> tag. See Bundlers and CDN.

UserAction

The detail of every userAction event is a UserAction, a union discriminated by type. The declarations:

export interface FilterSelection { /** First selected category, or 'All' when none are on. Kept for compatibility. */ filter: string /** The whole selection. Empty means no category filter. */ filters: string[] } export interface SelectFilterAction { type: 'select-filter' data: FilterSelection } export interface ShowPlaceAction { type: 'show-place' data: { placeId: string; alias: string | undefined } } export interface SelectDestinationAction { type: 'select-destination' data: { destinationId: string; alias: string | undefined } } export interface SearchAction { type: 'search' data: { searchTerm: string } } export interface ReturnToHomeAction { type: 'return-to-home' data: { filter: string } } export type UserAction = | SelectFilterAction | ShowPlaceAction | SelectDestinationAction | SearchAction | ReturnToHomeAction
typedataEmitted when
select-filter{ filter, filters }The visitor turns a category on or off. filters is the whole selection.
show-place{ placeId, alias }A place profile opens: card or map marker click, tenant deep link, or Back from the route screen.
select-destination{ destinationId, alias }The visitor clicks Pedestrian-friendly directions on a profile.
search{ searchTerm }A search runs for a new term.
return-to-home{ filter }The component goes back to its home screen from a profile or from search. filter is the selected category name, or an empty string when there are no categories.
  • Ids: placeId and destinationId are the place’s MapVX id, which is mapvxId on MVXPlace and id in PlaceResponse. alias is the place’s clientId: its alias in MapVX data, or its externalId when it has no alias, and undefined when it has neither. The alias key is always present.
  • cardSelected: this legacy event has no exported type. Its detail is the place’s MapVX id, so type it as CustomEvent<string> (see cardSelected).
  • Details: when each action fires, and how often, is described in Action types.

A typed listener, without any element typing:

import type { UserAction } from '@mapvx/web-components-ssr' const el = document.querySelector('mapvx-website') el?.addEventListener('userAction', (event) => { const action = (event as CustomEvent<UserAction>).detail switch (action.type) { case 'select-filter': case 'return-to-home': console.log('Category:', action.data.filter) break case 'show-place': console.log('Place:', action.data.placeId, action.data.alias) break case 'select-destination': console.log('Directions to:', action.data.destinationId) break case 'search': console.log('Search:', action.data.searchTerm) break default: { // Compile error here if a new action type is not handled above const unhandled: never = action console.warn('Unhandled action', unhandled) } } })

Each case narrows action.data to that member’s shape. The never assignment turns an unhandled member into a compile error, for example after an upgrade that adds one. Attach the listener to the element itself with the exact name userAction, because the event does not bubble (see Listening to events).

InitialData

The shape behind the initial-data attribute:

export interface InitialData { availablePlaces: PlaceResponse[] | null institutions: InstitutionResponse[] | null }
  • A JSON string: the attribute and the initialData property take this object serialized as JSON. prepareInitialData from @mapvx/web-components-ssr-helpers already resolves to that string, so pass it unchanged. An object set as the property throws a TypeError inside the component.
  • Raw API shapes: PlaceResponse and InstitutionResponse are the objects the MapVX API returns, with the id in id. The component converts them to MVXPlace and Institution, where the id is mapvxId.
  • Only these two keys: other keys are ignored, and a key set to null is skipped. The helper sets a key to null when its request gets an HTTP error status.
  • Where the type lives: the helper package does not export InitialData; import it from @mapvx/web-components-ssr.

Server code that checks the data before rendering:

import type { InitialData } from '@mapvx/web-components-ssr' import { prepareInitialData } from '@mapvx/web-components-ssr-helpers' const initialData = await prepareInitialData('YOUR_API_KEY') // JSON string const { availablePlaces, institutions } = JSON.parse(initialData) as InitialData console.log(`${availablePlaces?.length ?? 0} places, ${institutions?.length ?? 0} institutions`) // Pass initialData (the string) to the initial-data attribute, not the parsed object

Error handling and timeouts for the helper are covered in prepareInitialData.

In 1.6.1, using initial-data together with api-key lists every place twice. See the known issue.

Other models

The remaining exports describe the component’s internal state. None of them appears in the element’s attributes or events.

TypeShapeDescribes
AnimationStateenum: NotStarted = 0, Playing = 1, Paused = 2, Finished = 3, Stepping = 4The route animation. Stepping, added in 1.4.0 as the last member, advances the route one step per visitor action instead of playing on its own.
CategoryFiltersData{ name: string; placeData: string[] }A category on offer: its label and the MapVX ids of its places (empty for All). Also the payload of categoriesChange.
FormattedSchedule{ day: string; schedule: string[] }One row of the weekly hours. day can be a range such as Monday - Friday.
SearchData{ term: string; results: MVXPlace[] }A search term and its results.
CurrentLocation{ type: 'current-location'; title: 'Current location'; position: LatLng }The visitor’s position, used as a point of a route.
RoutePointMVXPlace or CurrentLocationA route origin or destination.

These declared values exist inside the bundle, but main.js does not export them (see Types only):

NameWhat it is
EMPTY_SEARCH_DATAA SearchData with an empty term and no results.
FALLBACK_IMAGE_URLThe placeholder image that cards and place profiles show when a place has neither photos nor a logo.
MEASUREMENT_IDThe measurement ID of MapVX’s Google Analytics property, which the component reports to (see Google Analytics).
toCurrentLocation(position)Converts a GeolocationPosition into a CurrentLocation.
isCurrentLocation(point)Type guard: the point is a CurrentLocation.
isPlace(point)Type guard: the point is an MVXPlace (it has a mapvxId).
isDealOrEventBanner(banner)Whether a banner is tagged deals or events.
extractBannerColor(description)The color declared in the first inline style attribute of a banner description, or #EE5845.
getSchedule(openingHours)Today’s hours as an HTML string: the previous day’s hours while an overnight interval is still open, or text such as Open on Monday when the place does not open today. Computed with the viewer’s clock and time zone.
prepareAllSchedules(openingHours)The weekly hours as FormattedSchedule[], starting on Monday. Consecutive days with the same hours share one row (the last row, which ends on Sunday, joins the first one when their hours match), and days without hours show Closed. The hours are HTML strings.

Maps SDK types

The component is built on @mapvx/web-js, the MapVX maps SDK, which is bundled inside main.js (1.6.1 bundles SDK version 3.1.0). The package re-exports the SDK’s data types, and their declarations are copied into public-api.d.ts, so you do not need to install @mapvx/web-js to use them.

TypeKindDescription
MVXPlaceclassA place: mapvxId, clientId, title, position, category, localizedCategory, address, openingHours, images, logo, banners, floors, parentId and parentInstitutionId.
InstitutionclassA group of places, such as a shopping mall: mapvxId, title, country, optional city, category, properties.
BannerclassA place banner: url, tags, urlAction, sameLink and an optional description that can contain HTML.
MVXRouteclassA route made of legs, with steps, duration (seconds) and length (meters) getters.
MVXRouteLegclassThe part of a route between two points: distance, duration, start and end locations, steps.
MVXRouteStepclassOne navigation step: instructions, distance, duration, locations, floors and elevatorStep.
MVXTransportclassTransport schedules and real-time routes.
MVXLocationinterfaceA LatLng with optional floorId and placeId.
CityFilterOptionunionAn entry of the city filter: an institution option (type: 'institution') or a parent-place option (type: 'parent-place', with parentPlaceId), each with filterId, name and institutionId.
OpeningHourstypeThe opening intervals of each day, keyed by DaysOfTheWeek.
OpeningTimeinterfaceOne interval: open and close as 24-hour times such as 09:00.
DaysOfTheWeektype'mo', 'tu', 'we', 'th', 'fr', 'sa' or 'su'.
LatLnginterface{ lat: number; lng: number }
InnerFloorinterfaceA floor of a building: key, index, level, name, defaultFloor.
PropertyinterfaceA property of a place or institution: title, subtitle and the optional icon, url and type. The category tabs come from the institution’s properties.
PlaceResponseinterfaceA place as the MapVX API returns it (id, title, lat, lng and more). Used in InitialData.
InstitutionResponseinterfaceAn institution as the MapVX API returns it. Used in InitialData.

MVXPlace, Institution, Banner and the route and transport types are declared as classes. Use them as types only: their constructors and static methods are not available to your code (Types only).

Element typing

The package does not type the <mapvx-website> element: it has no HTMLElementTagNameMap entry, no JSX IntrinsicElements entry and no event map. Without them, document.querySelector('mapvx-website') is typed as a plain Element | null, and TSX reports Property 'mapvx-website' does not exist on type 'JSX.IntrinsicElements'. Add a declaration file to your project. The declarations below were type-checked with TypeScript 5.9 and 6.0.

  • Any .d.ts file that the include of your tsconfig.json covers works. Do not give it the same name as a .ts or .tsx file in the same folder (for example mapvx-website.d.ts next to mapvx-website.tsx): TypeScript then skips the .d.ts file without any warning.
  • The DOM and React declarations can live in the same file.

DOM and events

This declaration types querySelector, createElement, the element’s properties and its two events:

// types/mapvx-website.d.ts import type { UserAction } from '@mapvx/web-components-ssr' export interface MapvxWebsiteEventMap extends HTMLElementEventMap { userAction: CustomEvent<UserAction> cardSelected: CustomEvent<string> } export interface MapvxWebsiteElement extends HTMLElement { apiKey: string institutionId: string initialData: string // a JSON string, never an object showCategoryFilters: boolean showCityFilter: boolean defaultToMap: boolean inheritFontFamily: boolean hideDeals: boolean showDealLabels: boolean cardWidth: number | undefined rowsPerPage: number addEventListener<K extends keyof MapvxWebsiteEventMap>( type: K, listener: (this: MapvxWebsiteElement, event: MapvxWebsiteEventMap[K]) => void, options?: boolean | AddEventListenerOptions, ): void addEventListener( type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions, ): void removeEventListener<K extends keyof MapvxWebsiteEventMap>( type: K, listener: (this: MapvxWebsiteElement, event: MapvxWebsiteEventMap[K]) => void, options?: boolean | EventListenerOptions, ): void removeEventListener( type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions, ): void } declare global { interface HTMLElementTagNameMap { 'mapvx-website': MapvxWebsiteElement } }

With it, no cast is needed:

const el = document.querySelector('mapvx-website') // MapvxWebsiteElement | null el?.addEventListener('userAction', (event) => { // event: CustomEvent<UserAction> if (event.detail.type === 'search') console.log('Search:', event.detail.data.searchTerm) }) el?.addEventListener('cardSelected', (event) => console.log('Card:', event.detail)) // string const created = document.createElement('mapvx-website') created.rowsPerPage = 3
  • The property types are the values the component uses after parsing its inputs. How each property accepts and returns values is described in JavaScript properties.
  • A misspelled event name, such as 'useraction', matches no entry of the event map. The listener then receives a plain Event, so reading event.detail is reported as an error.

Listener helper

When the element reference is not typed, for example a framework ref typed as HTMLElement, this helper gives you a typed UserAction and returns a function that removes the listener:

// on-user-action.ts import type { UserAction } from '@mapvx/web-components-ssr' export function onUserAction(element: Element, handler: (action: UserAction) => void): () => void { const listener = (event: Event) => handler((event as CustomEvent<UserAction>).detail) element.addEventListener('userAction', listener) return () => element.removeEventListener('userAction', listener) }
import { onUserAction } from './on-user-action' const el = document.querySelector('mapvx-website') if (el) { const stop = onUserAction(el, (action) => { if (action.type === 'show-place') console.log('Place:', action.data.placeId) }) // Call stop() to remove the listener, for example when your view unmounts }

React

TSX needs a JSX declaration for the tag. Both versions use the declare module 'react' form; the file must have a top-level import, as these do, for TypeScript to treat it as an augmentation of the react module.

// types/mapvx-website-react.d.ts import type { DetailedHTMLProps, HTMLAttributes } from 'react' import type { UserAction } from '@mapvx/web-components-ssr' // React 19 renders {true} as "" and drops {false}: accept strings only type BooleanAttribute = 'true' | 'false' interface MapvxWebsiteProps extends DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement> { 'api-key'?: string 'institution-id'?: string 'initial-data'?: string 'show-category-filters'?: BooleanAttribute 'show-city-filter'?: BooleanAttribute 'show-view-toggle'?: BooleanAttribute 'show-search-bar'?: BooleanAttribute 'show-drop-pin'?: BooleanAttribute 'selected-categories'?: string 'search-term'?: string 'full-width-map'?: BooleanAttribute 'hide-unselected-markers'?: BooleanAttribute 'default-to-map'?: BooleanAttribute 'inherit-font-family'?: BooleanAttribute 'hide-deals'?: BooleanAttribute 'show-deal-labels'?: BooleanAttribute 'card-width'?: number | string 'rows-per-page'?: number | string 'zoom'?: number | string 'center'?: string // React 19 listens to the event named after "on", with its exact case onuserAction?: (event: CustomEvent<UserAction>) => void oncardSelected?: (event: CustomEvent<string>) => void } declare module 'react' { namespace JSX { interface IntrinsicElements { 'mapvx-website': MapvxWebsiteProps } } }
import type { UserAction } from '@mapvx/web-components-ssr' export function Directory({ initialData }: { initialData?: string }) { const handleAction = (event: CustomEvent<UserAction>) => { const action = event.detail if (action.type === 'show-place') console.log('Place:', action.data.placeId) } return ( <mapvx-website api-key="YOUR_API_KEY" institution-id="YOUR_INSTITUTION_ID" initial-data={initialData} default-to-map="true" show-city-filter="false" rows-per-page={3} onuserAction={handleAction} oncardSelected={(event) => console.log('Card:', event.detail)} /> ) }
  • React 19 renders {true} as an empty attribute, which the component reads as false, and omits {false}, so on the first render the default applies (true for show-category-filters and show-city-filter). Typing the booleans as 'true' | 'false' turns both mistakes into compile errors.
  • The event props are onuserAction and oncardSelected: on followed by the event name with its exact case. onUserAction never fires, and this declaration rejects it.
  • @types/react 19 has no global JSX namespace, so a declare global { namespace JSX { ... } } block has no effect there.
  • This form was checked with @types/react 19.

Load the bundle in the browser only; see React and Next.js.

The JSX declaration applies to React TSX. With other frameworks, the DOM declaration and the listener helper type the element in your script code. Loading the bundle and configuring templates are covered in Vue, Angular and Other frameworks.

Last updated on