Possible Error: @types RendererProperties defines weak type

981
1
03-05-2019 06:16 PM
TristanLopus1
Emerging Contributor

In version 2.4 (Dec. 2017), TypeScript introduced the concept of a weak type. A weak type is any type that is defined by only optional properties.

Any type that contains nothing but a set of all-optional properties is considered to be weak.

As defined in the type declarations file for the ArcGIS API for JavaScript (node_modules/@types/arcgis-api-js/index.d.ts), the interface RendererProperties defines a weak type, since it specifies only one property and that property is optional. 

 export const Renderer: RendererConstructor;

  interface RendererProperties {
    /**
     * Authoring metadata only included in renderers generated from one of the Smart Mapping creator methods, such as ...
     *
     * [Read more...](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-Renderer.html#authoringInfo)
     */
    authoringInfo?: AuthoringInfoProperties;

  }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Typescript disallows assigning weak types to objects when there is no overlap in properties between the type declaration and the object's properties. In other words, even though all properties of a weak type are optional, an object must have at least one of them in order to be assigned that type.

In the case of the RendererProperties type, this means that no object can be assigned the type RendererProperties unless it has an authoringInfo property. This is a rather undesirable requirement, as there are many use cases for the Renderer type that do not necessitate an authoringInfo property.

For example, consider the following code from the official API sample code -- Sandbox link here.

var quakesRenderer = {
        type: "simple", // autocasts as new SimpleRenderer()
        symbol: {
          type: "simple-marker", // autocasts as new SimpleMarkerSymbol()
          style: "circle",
          size: 20,
          color: [211, 255, 0, 0],
          outline: {
            width: 1,
            color: "#FF0055",
            style: "solid"
          }
        },
        visualVariables: [
        {
          ... // omitted for brevity

        }]
      };‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

function createLayer(graphics) {

        layer = new FeatureLayer({
          source: graphics, // autocast as an array of esri/Graphic
          // create an instance of esri/layers/support/Field for each field object
          fields: fields, // This is required when creating a layer from Graphics
          objectIdField: "ObjectID", // This must be defined when creating a layer from Graphics
          renderer: quakesRenderer, // ** autocast attempts to assign type RendererProperties, but cannot
          popupTemplate: pTemplate
        });

        map.add(layer);
        return layer;
      }

‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

This example does not work in TypeScript. When the FeatureLayer constructor is called in line 23, TypeScript attempts to cast the object passed to it to type FeatureLayerProperties. This, in turn, requires that the value of the renderer property be cast to type RendererProperties. However, this cast fails, as RendererProperties is a weak type and quakesRenderer has no properties that overlap with it.

One fairly reasonable, very easy fix would be to add an index signature with type any to the RendererProperties interface to ensure that any properties will be accepted. This is perhaps a bit hacky, but it would work.

 interface RendererProperties {
    /**
     * Authoring metadata only included in renderers generated from one of the Smart Mapping creator methods, such as [sizeRendererCreator.createContinuousRenderer()](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-smartMapping-creators-size.html#createContinuousRenderer) or [colorRendererCreator.createContinuousRenderer()](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-smartMapping-creators-color.html#createContinuousRenderer). This includes information from UI elements such as sliders and selected classification methods and themes. This allows the authoring clients to save specific overridable settings so that next time it is accessed via the UI, their selections can be remembered.
     *
     * [Read more...](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-Renderer.html#authoringInfo)
     */
    authoringInfo?: AuthoringInfoProperties;

    [prop: string]: any;

  }

Am I missing something, or is this, in fact, an error in the API's type declarations?

Tags (1)
1 Reply
dangrussell
New Contributor

I agree that this is broken as far as how people probably expect TypeScript to work.

This post about a similar problem provides a workaround answer: https://community.esri.com/t5/arcgis-api-for-javascript/help-with-simplerenderer-using-react-typescr...

0 Kudos