Search code examples
typescriptpromisearcgis-js-apiesri-loader

Why are array elements passed into .then() accessible by name in Typescript?


I have started integrating our ArcGis JS template into the webpack build pipeline we are using.

In order to accomplish this, we need to refactor quiet a bit and need to start using the Esri-Loader (https://github.com/Esri/esri-loader), which essentially wraps dojos require function into a promise.

A really simple example looks like this:

start = () => {
    return EsriLoader.loadModules(['esri/Map', 'esri/views/MapView', "esri/Basemap"])
        .then(([Map, MapView, Basemap]) => {
            const map = new Map({
                basemap: "streets"
              });

              const view = new MapView({
                map: map,
                container: "map"
              });
        });
}

At first I tried writing the call to .then() like this: .then((Map, MapView, Basemap) => { ... }, but was receiving the following compiler error:

Argument of type '(Map: any, MapView: any, Basemap: any) => void' is not assignable to parameter of type '(value: any[]) => void | PromiseLike'.

Ok, so the signature does not add up:

function loadModules(modules: string[], loadScriptOptions?: ILoadScriptOptions): Promise<any[]>;

So the correct way to do this is like above: .then(([Map, MapView, Basemap]) => { ... }

And at this point my understanding has reached its limit. In the following method body I am able to call Map, MapView and BaseMap by their name, while I was expecting this to be an array, which I had to be accessing javascript-ish like Arguments[0][0], Arguments[0][1] and so on, since I did pass in only one object of type Array<any>.

Please explain to me why and how this is possible or if I am doing something horribly wrong here.


Solution

  • It's called destructuring.

    let [a, b, c] = result;
    

    it's the same as

    let a = result[0];
    let b = result[1];
    let c = result[2];
    

    Same goes for function args

    function ([a,b,c]) {
    }
    

    it's the same as

    function (args) {
      let a = args[0];
      let b = args[1];
      let c = args[2];
    }
    

    You can also do object destructuring:

    let { a, b, c } = item;
    

    same as:

    let a = item.a;
    let b = item.b;
    let c = item.c;
    

    In your case, the code can be written as:

    start = () => {
        return EsriLoader.loadModules(['esri/Map', 'esri/views/MapView', "esri/Basemap"])
            .then(modules => {
                const Map = modules[0];
                const MapView = modules[1];
                const Basemap = modules[2];
                const map = new Map({
                    basemap: "streets"
                  });
    
                  const view = new MapView({
                    map: map,
                    container: "map"
                  });
            });
    }