Initialize a typescript project:
npm init -y
npm i typescript --save-dev
Create app/index.ts
:
const username = "hhkaos";
const helloName = (name) => {
console.log(name);
};
helloName(username);
Manually compile the file: ./node_modules/typescript/bin/tsc app/index.ts
This will generate an app/index.js
. Open and check the generated code.
Manually run the compiled file node app/index.js
.
Any JS code is valid TS code (== TS is a superset of JS) but when using TypeScript, it will force us:
- To declare every variable
- To keep inmutable the type of each variable (unless you explicitly define it as
any
type).
Bellow we will learn how to configure the TS compiler to be more or less flexible/strict.
TypeScript allows us to define "contracts" in our code like:
- Which is the type of a variable
- Which properties must have and object
- In a function, the type of each parameter and the type returned
- etc.
Go to the TypeScript playground and try this:
// Basic types
var num: number = 2;
var today: Date = new Date();
var isEmpty: boolean = false;
var colors: string[] = ['red', 'green', 'blue'];
// Functions
const add = (a, b) => { // ES2015 arrow function
return a + b;
};
// add() receives a and b of type number, and return a number
const add = (a: number, b: number): number => {
return a + b;
};
// function with optional parameters
const printHello = (text?: string): void => {
console.log(`Hello ${text? text: "World"}`);
};
printHello();
printHello("Raul");
// function allowing multiple types for a parameter
function getlength(value: number | string): number {
if(typeof value === "number"){
return value.toString().length;
}else{
return value.length;
}
}
console.log(getlength("Raul"));
console.log(getlength(3.141516));
// Interfaces
interface Point{
x: number,
y: number
}
function printPoint(p: Point){
console.log(`x = ${p.x}, y= ${p.y}`);
}
const x = {
x: 123,
z: 123
}
printPoint(x);
Now check the type definitions (.D.TS) generated.
That file will provide to Visual Studio Code (and maybe other IDEs) enough knowledge to:
- Identify some coding errors while we are writing
- Extend the JS/CSS/HTML code autocompletion adding it also our own code and third party libraries.
Both things will save us time.
Create tsconfig.json
(TypeScript compiler options)
./node_modules/typescript/bin/tsc --init
Check error disapears but appears any
. Edit tsconfig.json
:
"noImplicitAny": false
Test options in the TypeScript Playground:
- Target: ES5 vs ES2017
- Type Checking
-
noImplicitAny: true
, the code bellow will fail:function fn(s) { console.log(s.subtr(3)); } fn(42);
-
strictFunctionTypes:true
function fn(x: string) { console.log("Hello, " + x.toLowerCase()); } type StringOrNumberFunc = (ns: string | number) => void; let func: StringOrNumberFunc = fn; func(10);
-
To automatically recompile TypeScript, add on package.json
:
"scripts": {
"dev": "tsc -w"
}
This will run the compiler in watch mode. Execute it with: npm run dev
Now, we are going to see a simple examplo of how we can modularize our code to better structure it.
Note: understanding how classes works and how TypeScript works will help us better understand how the API is structured.
For that lets create a new TS file declaring a ES6 Class: app/Map.ts
:
export class Map{
basemap;
center;
constructor(properties){
this.basemap = properties.basemap || "topo";
this.center = properties.center || {x: 0, y: 0};
}
get(property){
return this[property];
}
}
Check how TS translate it to prototype
because we are using "target": "es5",
in the tsconfig.json
.
Now import the class to the index.ts
and use it:
import { Map } from "./Map" ;
// ...
let myMap = new Map({
basemap: "streets"
});
console.log(myMap.get("basemap"));
console.log(myMap.center);
Run it with node app/index.js
and see how it works.
Now it's type to get prepare to leave node and compile our code to be browser-ready.
First update the TypeScript config (tsconfig.json
) to compile to AMD modules editing, and use "es2019" (recommended by the ArcGIS API for JS team).
Caveat: if you prefer to use local ESM, check other starter apps here.
"module": "amd",
"target": "es2019",
Notice how index.js
now uses require
to load the modules.
Next, remove the lastest adds in the index.ts
:
// import { Map } from "./Map" ;
// ...
// let myMap = new Map({
// basemap: "streets"
// });
// console.log(myMap.get("basemap"));
// console.log(myMap.center);
And add:
import MapView from "esri/views/MapView";
After addind that line you will get the following error: Cannot find module 'esri/views/MapView' or its corresponding type declarations.(2307)
It is because any time you use a third party library, you have to install the TypeScript type definitions. For the ArcGIS JS API you do it like this:
npm i @types/arcgis-js-api --save-dev
Now you will see that it doesn't fail.
Note: the path of the MapView needs to be the AMD path because we set the compile to AMD.
Next, add the following code to index.ts
:
new MapView({
map: {
basemap: "streets-navigation-vector"
},
container: "viewDiv",
center: [ -118.244, 34.052],
zoom: 12
});
Realize that now when leaving the cursor over a class name or a property, thanks to the type definitions:
- A tooltip appears with:
- The definition/description of the class/property
- And accepted parameters or values
- Links to the ArcGIS for JavaScript API Reference
- Each time we add a dot (.) after a variable or property of our map/layer/etc. VS code will show a list of properties and methods available
For example:
- Over
MapView
class: links to theMap
andMapView
classes and that it expects just one argumentMapViewProperties
(which is optional) - Over the property
center
: links to the documentation of the property in the API Reference but also a link to thePoint
class. It expects an instance of aPoint
, and object withtype: "point"
, and array of numbers orundefined
. - Over the
container
property: a link to the documentation of the property in the API Reference and that it expects anstring
,HTMLDivElement
or undefined. - After
view.
a list of properties and methods are displayed (scrollable).
Note: pressing Ctrl (Win) / CMD (Mac), you will be able to browse through the type definition. You can consider it also as a source of truth.
Now it's time to execute the code client-side.
Now create an index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://js.arcgis.com/4.20/esri/css/main.css">
<script src="https://js.arcgis.com/4.20"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div id="viewDiv"></div>
<script src="app/index.js"></script>
</body>
</html>
If you try to load it in a browser you wil notice it doesn't do anything, it is because we need to load it using require (remember, we are using AMD).
So lets use the dojoConfig included in the AMD of this version of the ArcGIS JS API to be able to use require(["app/index"]);
to load our code.
Add before the <script>
tag of the ArcIGS JS API:
<script>
var locationPath = location.pathname.replace(/\/[^\/]*$/, "");
window.dojoConfig = {
packages: [{
name: "app",
location: locationPath + "/app"
}]
};
</script>
And now replace:
- This line:
<script src="index.js"></script>
- For this line:
<script>require(["app/index"]);</script>
And voilà! there we have it.
We are going to migrate this JSAPI sample. Copy it and replace the index.ts
.
First we will have to replace the requires:
import Map from "esri/Map";
import MapView from "esri/views/MapView";
import GroupLayer from "esri/layers/GroupLayer";
import FeatureLayer from "esri/layers/FeatureLayer";
import ImageryLayer from "esri/layers/ImageryLayer";
import VectorTileLayer from "esri/layers/VectorTileLayer";
Reindent and then remove (or add // @ts-ignore
) the invalid property:
lastestWkid: 102003
Fix the problem with the autocast (known limitation of TS):
import SimpleFillSymbol from "esri/symbols/SimpleFillSymbol";
// ...
symbol: new SimpleFillSymbol({
color: "black"
})
Now we will see how to use the "ArcGIS API for JavaScript Snippets" extension and how to create custom "Users snippets".
- ArcGIS API for JavaScript Snippets
- VSCode ArcGIS JS API 4.x snippets Cheat Sheet Cheat Sheet
- How to add new snippets using VS Code User Snippets
- Visual Studio Code Snippets Builder
- Additional VS code user snippets https://github.com/Esri/arcgis-js-vscode-snippets/blob/master/contributing.md#contributing-guidelines
Use search
snippet to add the search widget:
import Search from "esri/widgets/Search";
const searchWidget = new Search({
view: view
});
view.ui.add(searchWidget, "top-right");
Resources:
- How to compile TypeScript file (*.ts) to JavaScript (*.js)
- TypeScript as a superset of JavaScript
- Very basic intro to some TypeScript capabilities
- Basic TypeScript compiler options
- Import basic local class
- Installing TypeScript type definitions
- Import the ArcGIS API for JS (AMD & CDN)
- Type definitions and code autocompletion
- Load Execute code client-side
- Migrate a sample app
- Benefit from using VS code snippets
- TS resources to keep learning