Connecting the API using TypeScript
Note
In Mappable Account, log in or create a new account. The main page will display a key that will work for any Mappable service.
The key is activated within 15 minutes after you receive it.
Regular connection
<!DOCTYPE html>
<html>
<head>
<!-- Replace YOUR_API_KEY with the real key -->
<script src="https://js.api.mappable.world/v3/?apikey=YOUR_API_KEY&lang=en_US"></script>
<script type="module" src="index.js"></script>
</head>
<body>
<div id="app" style="width: 600px; height: 400px"></div>
</body>
</html>
import type { MMapLocationRequest } from 'mappable';
async function initMap(): Promise<void> {
await mappable.ready;
const LOCATION: MMapLocationRequest = {
center: [25.229762, 55.289311],
zoom: 9
};
const { MMap, MMapDefaultSchemeLayer } = mappable;
const map = new MMap(document.getElementById('app'), { location: LOCATION });
map.addChild(new MMapDefaultSchemeLayer({}));
}
initMap();
{
"compilerOptions": {
"target": "es2015",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"esModuleInterop": true,
"moduleResolution": "node",
"typeRoots": [
"./node_modules/@types",
"./node_modules/@mappable-world/mappable-types"
],
"paths": {
"mappable": [
"./node_modules/@mappable-world/mappable-types"
]
}
}
}
{
"devDependencies": {
"@mappable-world/mappable-types": "^0.0.10",
"http-server": "14.1.1",
"typescript": "5.2.2"
},
"scripts": {
"compile": "./node_modules/.bin/tsc",
"start": "npx http-server ."
}
}
Set dependencies, compile TypeScript
, and run a local server:
npm install
npm run compile
npm run start
Open the app
Specifics of regular connection
-
In
package.json
, add a dev dependency on the@mappable-world/mappable-types
package.We recommend installing the latest version:
npm i --save-dev @mappable-world/mappable-types@latest
-
In
tsconfig.json
, setcompilerOptions.typeRoots
with a list of paths to type files. Add a path to the@mappable-world/mappable-types
package there to make themappable
namespace with types appear in the global scope.Note
The
mappable
namespace contains all the class types provided by the JS API, but they are not available in the runtime environment untilmappable.ready
is resolved. -
In
tsconfig.json
, setcompilerOptions.paths
, informing the TS compiler that the contents of the importedmappable
package should be searched for at the specified path. This enables you to import types in project files as if they were located not at@mappable-world/mappable-types
, but in themappable
package:import type { MMapLocationRequest } from 'mappable';
All types must be imported from the root.
The internal structure isn't guaranteed and can change over time.
-
Specify the
type="module"
attribute in thescript
tag that loads the compiled JS project so that the browser enablesESM
support in JS files.If this is not done in the example, an error will occur:
SyntaxError: Unexpected token 'export {}'
Connecting via top-level-await (recommended)
<!DOCTYPE html>
<html>
<head>
<!-- replace YOUR_API_KEY with the real key -->
<script src="https://js.api.mappable.world/v3/?apikey=YOUR_API_KEY&lang=en_US"></script>
<script type="module" src="index.js"></script>
</head>
<body>
<div id="app" style="width: 600px; height: 400px"></div>
</body>
</html>
import type { MMapLocationRequest } from 'mappable'
import { MMap, MMapDefaultSchemeLayer } from './lib/mappable.js'
const LOCATION: MMapLocationRequest = {
center: [25.229762, 55.289311],
zoom: 9
};
const map = new MMap(
document.getElementById('app'),
{
location: LOCATION
}
);
map.addChild(new MMapDefaultSchemeLayer());
await mappable.ready;
export const {MMap, MMapDefaultSchemeLayer} = mappable;
{
"compilerOptions": {
"target": "es2017",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"typeRoots": [
"./node_modules/@types",
"./node_modules/@mappable-world/mappable-types"
],
"paths": {
"mappable": [
"./node_modules/@mappable-world/mappable-types"
]
}
}
}
{
"devDependencies": {
"@mappable-world/mappable-types": "^0.0.10",
"http-server": "14.1.1",
"typescript": "5.2.2"
},
"scripts": {
"compile": "./node_modules/.bin/tsc",
"start": "npx http-server ."
}
}
Set dependencies, compile TypeScript
, and run a local server:
npm install
npm run compile
npm run start
Open the app
Specifics
-
Specify the
type="module"
attribute in the "script" tag that loads the compiled project JS to enable ECMAScript Modules (ESM) and top-level-await support:<script type="module" src="index.js"></script>
ESM support when using bundlers
If you're building a project using a bundler (for example, Webpack), add
"type": "module"
topackage.json
-
In
tsconfig.json
, for top-level-await to operate correctly, thecompilerOptions.module
parameter must be set to one of the following values:es2022
,esnext
,system
, orpreserve
. ThecompilerOptions.target
parameter must be set toes2017
or higher. -
In
lib/mappable.ts
, wait until the JS API is fully loaded and then export the necessary map components so that they can be used in other parts of the project:await mappable.ready; export const {MMap, MMapDefaultSchemeLayer} = mappable;
-
The use of top-level-await in
lib/mappable.ts
guarantees thatmappable.ready
is executed before the map components are imported, so the project code can be shorter and cleaner (the asynchronous initMap function is no longer needed):import { MMap, MMapDefaultSchemeLayer } from './lib/mappable.js' const map = new MMap({...});
Connecting with Webpack
Method 1
<!DOCTYPE html>
<html>
<head>
<!-- replace YOUR_API_KEY with the real key -->
<script src="https://js.api.mappable.world/v3/?apikey=YOUR_API_KEY&lang=en_US"></script>
<script src="build/bundle.js"></script>
</head>
<body>
<div id="app" style="width: 600px; height: 400px"></div>
</body>
</html>
import { type MMapLocationRequest } from 'mappable';
async function initMap() {
await mappable.ready;
const LOCATION: MMapLocationRequest = {
center: [25.229762, 55.289311],
zoom: 9
};
const { MMap, MMapDefaultSchemeLayer } = mappable;
const map = new MMap(document.getElementById('app'), {location: LOCATION});
map.addChild(new MMapDefaultSchemeLayer({}));
}
initMap();
{
"compilerOptions": {
"target": "es2015",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"esModuleInterop": true,
"moduleResolution": "node",
"typeRoots": [
"./node_modules/@types",
"./node_modules/@mappable-world/mappable-types"
],
"paths": {
"mappable": [
"./node_modules/@mappable-world/mappable-types"
]
}
},
}
const path = require('path');
module.exports = {
mode: 'development',
entry: './index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build'),
},
devtool: 'cheap-source-map'
};
{
"scripts": {
"compile": "./node_modules/.bin/tsc",
"build": "webpack",
"start": "npx http-server ."
},
"devDependencies": {
"@mappable-world/mappable-types": "^0.0.10",
"http-server": "14.1.1",
"typescript": "5.2.2",
"webpack": "5.88.2",
"webpack-cli": "5.1.4"
}
}
Set dependencies, compile TypeScript
, build a project, and run a local server:
npm install
npm run compile
npm run build
npm run start
Open the app
This method is no different from the previous connection. It only adds a step of building from project JS
files into a single build/bundle.js
Method 2
<!DOCTYPE html>
<html>
<head>
<script src="build/bundle.js"></script>
</head>
<body>
<div id="app" style="width: 600px; height: 400px"></div>
</body>
</html>
import type { MMapLocationRequest } from '@mappable-world/mappable-types';
import {MMap, MMapDefaultSchemeLayer} from '@mappable-world/mappable-types';
const LOCATION: MMapLocationRequest = {
center: [37.623082, 55.75254],
zoom: 9
};
const map = new MMap(document.getElementById('app'), {location: LOCATION});
map.addChild(new MMapDefaultSchemeLayer({}));
{
"compilerOptions": {
"target": "es2015",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"esModuleInterop": true,
"moduleResolution": "node",
"typeRoots": [
"./node_modules/@types",
"./node_modules/@mappable-world/mappable-types"
]
},
}
const path = require('path');
module.exports = {
mode: 'development',
entry: './index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build'),
},
externals: {
'@mappable-world/mappable-types': [
`promise new Promise((resolve) => {
if (typeof mappable !== 'undefined') {
return mappable.ready.then(() => resolve(mappable));
}
const script = document.createElement('script');
script.src = "https://js.api.mappable.world/v3/?apikey=YOUR_API_KEY&lang=en_US";
script.onload = () => {
mappable.ready.then(() => resolve(mappable));
};
document.head.appendChild(script);
})`
]
},
devtool: 'cheap-source-map'
};
{
"scripts": {
"compile": "./node_modules/.bin/tsc",
"build": "webpack",
"start": "npx http-server ."
},
"devDependencies": {
"@mappable-world/mappable-types": "^0.0.10",
"http-server": "14.1.1",
"typescript": "5.2.2",
"webpack": "5.88.2",
"webpack-cli": "5.1.4"
}
}
Set dependencies, compile TypeScript
, build a project, and run a local server:
npm install
npm run compile
npm run build
npm run start
Open the app
Specifics
-
You no longer need to connect the
<script>
tag in theHTML
document header — Webpack does this for you. -
In
webpack.config.js
, declare the external@mappable-world/mappable-types
variable where you need to specify a path to the API loader and where themappable.ready
promise is resolved.This makes it possible to import JS API types and classes in the project code as if the code were delivered not via a global variable, but via an
npm
package@mappable-world/mappable-types
:// Importing types import type { MMapLocationRequest } from '@mappable-world/mappable-types'; // Importing runtime code import {MMap, MMapDefaultSchemeLayer} from '@mappable-world/mappable-types';
-
tsconfig.json
no longer needs thecompilerOptions.paths.mappable
setting. -
In this case, fully loaded JS API modules become available and
mappable.ready
execution is guaranteed in the built projectJS
file, so the project code can be shorter and cleaner (the asynchronousinitMap
function is no longer needed).import type { MMapLocationRequest } from '@mappable-world/mappable-types'; import {MMap, MMapDefaultSchemeLayer} from '@mappable-world/mappable-types'; const {MMap} = mappable; const map = new MMap({...});
Setting up an alias
Note that in the last example, import is performed from a package named @mappable-world/mappable-types
. You can change this name using an alias in package.json
:
{
"devDependencies": {
// ...
"@mappable-world/mappable": "npm:@mappable-world/mappable-types@0.0.10",
// ...
}
}
After that, remember to update the external variable name in webpack.config.js
:
module.exports = {
//...
externals: {
'@mappable-world/mappable': [
// ...
]
}
}
After all the changes, you can import types and classes from the @mappable-world/mappable
package:
import type { MMapLocationRequest } from '@mappable-world/mappable';
import {MMap, MMapDefaultSchemeLayer} from '@mappable-world/mappable';