Categories
Visx

Add Heat Maps into Our React App with the Visx Library

Visx is a library that lets us add graphics to our React app easily.

In this article, we’ll look at how to use it to add heat maps into our React app.

Install Required Packages

We have to install a few modules.

To get started, we run:

npm i @visx/group @visx/heatmap @visx/mock-data @visx/responsive @visx/scale

to install the packages.

Add the Heatmaps

We can add the heatmaps by writing:

import React from "react";
import { Group } from "@visx/group";
import genBins from "@visx/mock-data/lib/generators/genBins";
import { scaleLinear } from "@visx/scale";
import { HeatmapCircle, HeatmapRect } from "@visx/heatmap";

const hot1 = "#77312f";
const hot2 = "#f33d15";
const cool1 = "#122549";
const cool2 = "#b4fbde";
const background = "#28272c";

const binData = genBins(/* length = */ 16, /* height = */ 16);

function max(data, value) {
  return Math.max(...data.map(value));
}

function min(data, value) {
  return Math.min(...data.map(value));
}
const bins = (d) => d.bins;
const count = (d) => d.count;

const colorMax = max(binData, (d) => max(bins(d), count));
const bucketSizeMax = max(binData, (d) => bins(d).length);

// scales
const xScale = scaleLinear({
  domain: [0, binData.length]
});
const yScale = scaleLinear({
  domain: [0, bucketSizeMax]
});
const circleColorScale = scaleLinear({
  range: [hot1, hot2],
  domain: [0, colorMax]
});
const rectColorScale = scaleLinear({
  range: [cool1, cool2],
  domain: [0, colorMax]
});
const opacityScale = scaleLinear({
  range: [0.1, 1],
  domain: [0, colorMax]
});
const defaultMargin = { top: 10, left: 20, right: 20, bottom: 110 };

const Example = ({
  width,
  height,
  events = false,
  margin = defaultMargin,
  separation = 20
}) => {
  const size =
    width > margin.left + margin.right
      ? width - margin.left - margin.right - separation
      : width;
  const xMax = size / 2;
  const yMax = height - margin.bottom - margin.top;
  const binWidth = xMax / binData.length;
  const binHeight = yMax / bucketSizeMax;
  const radius = min([binWidth, binHeight], (d) => d) / 2;

xScale.range([0, xMax]);
  yScale.range([yMax, 0]);

return width < 10 ? null : (
    <svg width={width} height={height}>
      <rect
        x={0}
        y={0}
        width={width}
        height={height}
        rx={14}
        fill={background}
      />
      <Group top={margin.top} left={margin.left}>
        <HeatmapCircle
          data={binData}
          xScale={(d) => xScale(d) ?? 0}
          yScale={(d) => yScale(d) ?? 0}
          colorScale={circleColorScale}
          opacityScale={opacityScale}
          radius={radius}
          gap={2}
        >
          {(heatmap) =>
            heatmap.map((heatmapBins) =>
              heatmapBins.map((bin) => (
                <circle
                  key={`heatmap-circle-${bin.row}-${bin.column}`}
                  className="visx-heatmap-circle"
                  cx={bin.cx}
                  cy={bin.cy}
                  r={bin.r}
                  fill={bin.color}
                  fillOpacity={bin.opacity}
                  onClick={() => {
                    if (!events) return;
                    const { row, column } = bin;
                    alert(JSON.stringify({ row, column, bin: bin.bin }));
                  }}
                />
              ))
            )
          }
        </HeatmapCircle>
      </Group>
      <Group top={margin.top} left={xMax + margin.left + separation}>
        <HeatmapRect
          data={binData}
          xScale={(d) => xScale(d) ?? 0}
          yScale={(d) => yScale(d) ?? 0}
          colorScale={rectColorScale}
          opacityScale={opacityScale}
          binWidth={binWidth}
          binHeight={binWidth}
          gap={2}
        >
          {(heatmap) =>
            heatmap.map((heatmapBins) =>
              heatmapBins.map((bin) => (
                <rect
                  key={`heatmap-rect-${bin.row}-${bin.column}`}
                  className="visx-heatmap-rect"
                  width={bin.width}
                  height={bin.height}
                  x={bin.x}
                  y={bin.y}
                  fill={bin.color}
                  fillOpacity={bin.opacity}
                  onClick={() => {
                    if (!events) return;
                    const { row, column } = bin;
                    alert(JSON.stringify({ row, column, bin: bin.bin }));
                  }}
                />
              ))
            )
          }
        </HeatmapRect>
      </Group>
    </svg>
  );
};

export default function App() {
  return (
    <div className="App">
      <Example width={500} height={300} />
    </div>
  );
}

We define the color codes for the heatmap at the top of the code.

binData has the data for the heatmap.

max and min returns the max and min values from the data.

bins and count are the getter methods for the data.

We get the max values for the color and bucket size with the colorMax and bucketSizeMax functions.

Next, we computed the xScale and yScale for the heatmaps to get the range of the values for the heatmap.

circleColorScale and rectColorScale are the color scales for the heatmap’s circles or rectangles.

opacityStyle have the opacity scale for the circles or rectangles.

In the Example component we get the width of the heatmap.

binWidth and binHeight have the width and height of the bins in the heatmap.

radius have the radius for the circles in the heatmap.

We pass all the variables into the HeatmapCircle component to create a heatmap with circles.

And the HeatmapRect component does the same to create a heatmap with rectangles.

The tiles are rendered in the render prop of each. We render circle or rect depending on the heatmap type.

Conclusion

We can create a heatmap with different kinds of tiles in a React app with the Visx library.

Categories
Visx

Add TreeMaps into Our React App with the Visx Library

Visx is a library that lets us add graphics to our React app easily.

In this article, we’ll look at how to use it to add treemaps into our React app.

Install Required Packages

We have to install a few modules.

To get started, we run:

npm i @visx/group @visx/hierarchy @visx/mock-data @visx/responsive @visx/scale

to install the packages.

Add the TreeMap

We can add the treemap into our React app by writing:

import React, { useState } from "react";
import { Group } from "@visx/group";
import {
  Treemap,
  hierarchy,
  stratify,
  treemapSquarify,
  treemapBinary,
  treemapDice,
  treemapResquarify,
  treemapSlice,
  treemapSliceDice
} from "@visx/hierarchy";
import shakespeare from "@visx/mock-data/lib/mocks/shakespeare";
import { scaleLinear } from "@visx/scale";

const color1 = "#f3e9d2";
const color2 = "#4281a4";
const background = "#114b5f";

const colorScale = scaleLinear({
  domain: [0, Math.max(...shakespeare.map((d) => d.size || 0))],
  range: [color2, color1]
});

const data = stratify()
  .id((d) => d.id)
  .parentId((d) => d.parent)(shakespeare)
  .sum((d) => d.size || 0);

const tileMethods = {
  treemapSquarify,
  treemapBinary,
  treemapDice,
  treemapResquarify,
  treemapSlice,
  treemapSliceDice
};

const defaultMargin = { top: 10, left: 10, right: 10, bottom: 10 };

function Example({ width, height, margin = defaultMargin }) {
  const [tileMethod, setTileMethod] = useState("treemapSquarify");
  const xMax = width - margin.left - margin.right;
  const yMax = height - margin.top - margin.bottom;
  const root = hierarchy(data).sort((a, b) => (b.value || 0) - (a.value || 0));

  return width < 10 ? null : (
    <div>
      <label>tile method</label>{" "}
      <select
        onClick={(e) => e.stopPropagation()}
        onChange={(e) => setTileMethod(e.target.value)}
        value={tileMethod}
      >
        {Object.keys(tileMethods).map((tile) => (
          <option key={tile} value={tile}>
            {tile}
          </option>
        ))}
      </select>
      <div>
        <svg width={width} height={height}>
          <rect width={width} height={height} rx={14} fill={background} />
          <Treemap
            top={margin.top}
            root={root}
            size={[xMax, yMax]}
            tile={tileMethods[tileMethod]}
            round
          >
            {(treemap) => (
              <Group>
                {treemap
                  .descendants()
                  .reverse()
                  .map((node, i) => {
                    const nodeWidth = node.x1 - node.x0;
                    const nodeHeight = node.y1 - node.y0;
                    return (
                      <Group
                        key={`node-${i}`}
                        top={node.y0 + margin.top}
                        left={node.x0 + margin.left}
                      >
                        {node.depth === 1 && (
                          <rect
                            width={nodeWidth}
                            height={nodeHeight}
                            stroke={background}
                            strokeWidth={4}
                            fill="transparent"
                          />
                        )}
                        {node.depth > 2 && (
                          <rect
                            width={nodeWidth}
                            height={nodeHeight}
                            stroke={background}
                            fill={colorScale(node.value || 0)}
                          />
                        )}
                      </Group>
                    );
                  })}
              </Group>
            )}
          </Treemap>
        </svg>
      </div>
    </div>
  );
}

export default function App() {
  return (
    <div className="App">
      <Example width={500} height={300} />
    </div>
  );
}

We add the colors for the treemap partitions with the color1 and color2 variables.

background has the background color.

We create the colorScale variable to create color variants for the partitions.

Then we convert the data into a structure that can be used with the treemap with the stratify method.

Next, in the Example component, we add a dropdown to display the tile method choices.

This lets us set the tile format for the treemap.

After this, we add the Treemap component to add the treemap.

In its render prop, we call descendants to get the descendants.

Then we call reverse to reverse the data.

map maps them to rect s so that we render the partitions.

We render them differently depending on the depth level.

Conclusion

We can add treemaps easily into our React app with the Visx library.

Categories
Visx

Add Box Plots into Our React App with the Visx Library

Visx is a library that lets us add graphics to our React app easily.

In this article, we’ll look at how to use it to add box plots into our React app.

Install Required Packages

We have to install a few modules.

To get started, we run:

npm i @visx/gradient @visx/group @visx/mock-data @visx/pattern @visx/responsive @visx/scale @visx/stats @visx/tooltip

to install the packages.

Add Box Plots

Now we can add the box plots with:

import React from "react";
import { Group } from "@visx/group";
import { ViolinPlot, BoxPlot } from "@visx/stats";
import { LinearGradient } from "@visx/gradient";
import { scaleBand, scaleLinear } from "@visx/scale";
import genStats from "@visx/mock-data/lib/generators/genStats";
import {
  Tooltip,
  defaultStyles as defaultTooltipStyles,
  useTooltip
} from "@visx/tooltip";
import { PatternLines } from "@visx/pattern";

const data = genStats(5);
const x = (d) => d.boxPlot.x;
const min = (d) => d.boxPlot.min;
const max = (d) => d.boxPlot.max;
const median = (d) => d.boxPlot.median;
const firstQuartile = (d) => d.boxPlot.firstQuartile;
const thirdQuartile = (d) => d.boxPlot.thirdQuartile;
const outliers = (d) => d.boxPlot.outliers;

const Example = ({ width, height }) => {
  const {
    tooltipOpen,
    tooltipLeft,
    tooltipTop,
    tooltipData,
    hideTooltip,
    showTooltip
  } = useTooltip();

  const xMax = width;
  const yMax = height - 120;
  const xScale = scaleBand({
    range: [0, xMax],
    round: true,
    domain: data.map(x),
    padding: 0.4
  });

  const values = data.reduce((allValues, { boxPlot }) => {
    allValues.push(boxPlot.min, boxPlot.max);
    return allValues;
  }, []);
  const minYValue = Math.min(...values);
  const maxYValue = Math.max(...values);

  const yScale = scaleLinear({
    range: [yMax, 0],
    round: true,
    domain: [minYValue, maxYValue]
  });

  const boxWidth = xScale.bandwidth();
  const constrainedWidth = Math.min(40, boxWidth);

  return width < 10 ? null : (
    <div style={{ position: "relative" }}>
      <svg width={width} height={height}>
        <LinearGradient id="statsplot" to="#8b6ce7" from="#87f2d4" />
        <rect
          x={0}
          y={0}
          width={width}
          height={height}
          fill="url(#statsplot)"
          rx={14}
        />
        <PatternLines
          id="hViolinLines"
          height={3}
          width={3}
          stroke="#ced4da"
          strokeWidth={1}
          orientation={["horizontal"]}
        />
        <Group top={40}>
          {data.map((d, i) => (
            <g key={i}>
              <ViolinPlot
                data={d.binData}
                stroke="#dee2e6"
                left={xScale(x(d))}
                width={constrainedWidth}
                valueScale={yScale}
                fill="url(#hViolinLines)"
              />
              <BoxPlot
                min={min(d)}
                max={max(d)}
                left={xScale(x(d)) + 0.3 * constrainedWidth}
                firstQuartile={firstQuartile(d)}
                thirdQuartile={thirdQuartile(d)}
                median={median(d)}
                boxWidth={constrainedWidth * 0.4}
                fill="#FFFFFF"
                fillOpacity={0.3}
                stroke="#FFFFFF"
                strokeWidth={2}
                valueScale={yScale}
                outliers={outliers(d)}
                minProps={{
                  onMouseOver: () => {
                    showTooltip({
                      tooltipTop: yScale(min(d)) ?? 0 + 40,
                      tooltipLeft: xScale(x(d)) + constrainedWidth + 5,
                      tooltipData: {
                        min: min(d),
                        name: x(d)
                      }
                    });
                  },
                  onMouseLeave: () => {
                    hideTooltip();
                  }
                }}
                maxProps={{
                  onMouseOver: () => {
                    showTooltip({
                      tooltipTop: yScale(max(d)) ?? 0 + 40,
                      tooltipLeft: xScale(x(d)) + constrainedWidth + 5,
                      tooltipData: {
                        max: max(d),
                        name: x(d)
                      }
                    });
                  },
                  onMouseLeave: () => {
                    hideTooltip();
                  }
                }}
                boxProps={{
                  onMouseOver: () => {
                    showTooltip({
                      tooltipTop: yScale(median(d)) ?? 0 + 40,
                      tooltipLeft: xScale(x(d)) + constrainedWidth + 5,
                      tooltipData: {
                        ...d.boxPlot,
                        name: x(d)
                      }
                    });
                  },
                  onMouseLeave: () => {
                    hideTooltip();
                  }
                }}
                medianProps={{
                  style: {
                    stroke: "white"
                  },
                  onMouseOver: () => {
                    showTooltip({
                      tooltipTop: yScale(median(d)) ?? 0 + 40,
                      tooltipLeft: xScale(x(d)) + constrainedWidth + 5,
                      tooltipData: {
                        median: median(d),
                        name: x(d)
                      }
                    });
                  },
                  onMouseLeave: () => {
                    hideTooltip();
                  }
                }}
              />
            </g>
          ))}
        </Group>
      </svg>

      {tooltipOpen && tooltipData && (
        <Tooltip
          top={tooltipTop}
          left={tooltipLeft}
          style={{
            ...defaultTooltipStyles,
            backgroundColor: "#283238",
            color: "white"
          }}
        >
          <div>
            <strong>{tooltipData.name}</strong>
          </div>
          <div style={{ marginTop: "5px", fontSize: "12px" }}>
            {tooltipData.max && <div>max: {tooltipData.max}</div>}
            {tooltipData.thirdQuartile && (
              <div>third quartile: {tooltipData.thirdQuartile}</div>
            )}
            {tooltipData.median && <div>median: {tooltipData.median}</div>}
            {tooltipData.firstQuartile && (
              <div>first quartile: {tooltipData.firstQuartile}</div>
            )}
            {tooltipData.min && <div>min: {tooltipData.min}</div>}
          </div>
        </Tooltip>
      )}
    </div>
  );
};

export default function App() {
  return (
    <div className="App">
      <Example width={500} height={300} />
    </div>
  );
}

The data variable has the data for the boxplot.

Then we add the getter methods below it.

In the Example component, we call the useTooltip hook to show tooltips when we hover over the boxplots.

showTooltip shows the tooltip. hideTooltip hides the tooltip.

We add the values variable to gather the values needed for the boxplots.

yScale has the scale for the y-axis.

To add the boxplots, we call data.map to map the data values box plot components.

We use the ViolinPlot component to render the violin plot surrounding the boxplot.

Then we use the BoxPlot component to render the boxplot.

We pass in all the getter methods as props into ViolinPlot and BoxPlot .

We call showTooltip in the onMouseOver method to show a tooltip when we hover over the boxplot.

And in the onMouseLeave handler, we call hideTooltip to hide the tooltips when we move away from the boxplot.

minProps takes handlers that runs when we hover over the bottom of the boxplot.

maxProps takes handlers that runs when we hover over the top of the boxplot.

boxProps takes handlers that runs when we hover over the boxes of the boxplot.

medianProps takes handlers that runs when we hover over the median point of the boxplot.

Finally, we add the tooltip content with the Tooltip component.

Now we should see a box and violin plot. And when we hover over the whiskers or the boxes, we see a tooltip with the values.

Conclusion

We can add box and violin plots into our React app with the Visx library.

Categories
Visx

Add Polygons into Our React App with the Visx Library

Visx is a library that lets us add graphics to our React app easily.

In this article, we’ll look at how to use it to add polygons into our React app.

Install Required Packages

We have to install a few modules.

To get started, we run:

npm i @visx/gradient @visx/group @visx/responsive @visx/scale @visx/shape

to install the packages.

Add Polygons

To add the polygons, we write:

import React from "react";
import { Polygon } from "@visx/shape";
import { Group } from "@visx/group";
import { scaleBand } from "@visx/scale";
import { GradientPinkRed } from "@visx/gradient";

export const background = "#7f82e3";
const polygonSize = 25;
const defaultMargin = { top: 10, right: 10, bottom: 10, left: 10 };

const polygons = [
  {
    sides: 3,
    fill: "rgb(174, 238, 248)",
    rotate: 90
  },
  {
    sides: 4,
    fill: "lightgreen",
    rotate: 45
  },
  {
    sides: 6,
    fill: "rgb(229, 130, 255)",
    rotate: 0
  },
  {
    sides: 8,
    fill: "url(#polygon-pink)",
    rotate: 0
  }
];

const yScale = scaleBand({
  domain: polygons.map((p, i) => i),
  padding: 0.8
});

const Example = ({ width, height, margin = defaultMargin }: PolygonProps) => {
  yScale.rangeRound([0, height - margin.top - margin.bottom]);
  const centerX = (width - margin.left - margin.right) / 2;
  return (
    <svg width={width} height={height}>
      <rect width={width} height={height} fill={background} rx={14} />
      <GradientPinkRed id="polygon-pink" />
      {polygons.map((polygon, i) => (
        <Group
          key={`polygon-${i}`}
          top={(yScale(i) || 0) + polygonSize / 2}
          left={margin.left + centerX}
        >
          <Polygon
            sides={polygon.sides}
            size={polygonSize}
            fill={polygon.fill}
            rotate={polygon.rotate}
          />
        </Group>
      ))}
    </svg>
  );
};

export default function App() {
  return (
    <div className="App">
      <Example width={500} height={300} />
    </div>
  );
}

The background variable has the background’s color.

polygonSize is the size of each polygon in pixels.

We create the polygons array with the properties of the polygons.

We set the number of sides with the sides .

fill is the background of the polygon.

rotate is the number of degrees to rotate it.

In the Example component, we add the polygons onto the screen with the polygons.map callback.

We add the Polygon component with the props to set the sides, fill, and rotation angle.

Conclusion

We can add polygons into our React app with the Visx library.

Categories
JavaScript Basics

Check JavaScript Variable Data Types with the Typeof Operator

The typeof operator in JavaScript is useful for checking primitive types.

JavaScript is a loosely typed or a dynamically typed language. This means that a variable that’s declare with one type can be converted to another type without explicitly converting the data to another type. Variables can also contain any type at any time depending on what’s assigned. JavaScript has multiple data types. There are 7 primitive data types and an object type. The 7 primitive types are boolean, null, undefined, number, BigInt, string and symbol. Since there are different data types and they a variable or an object’s properties’ types can change anything, we need a way to check for the type of data of an variable or an object’s property.

To check for the type of an object’s property or a variable, we use the typeof operator of an object. It lets us get the type name of an object or its properties with as a string. We can use it as allows:

typeof x

Where x is a variable’s name. This is the only operand of the typeof operator. The check the type of an object’s property, we can write:

typeof x.prop

With the code above we can conveniently get the type of the prop property of x . The typeof operator returns a string containing the name of the type of the operand. It can return the following types names as a string:

  • Objects with the undefined type will return 'undefined'
  • Objects with the null type will return 'object'
  • Objects with the boolean type will return 'boolean'
  • Objects with the number type will return 'number'
  • Objects with the BigInt type will return 'bigint'
  • Objects with the String type will return 'string'
  • Objects with the Symbol type will return 'symbol'
  • Objects with the Function type will return 'function'
  • Any other types of object will return 'object'

We can use the typeof operator like in the following examples:

Numbers

The following operands will return 'number' if the typeof operator is applied to it. Therefore, all of the expressions when logged will output true .

typeof 1 === 'number';
typeof 3.1 === 'number';
typeof(2) === 'number';
typeof Math.LN10 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number';
typeof Number('2') === 'number';
typeof Number('shoe') === 'number';

The number type is a double precision 64 bit number that can have values between negative 2 to the 53rd power minus one to 2 to the 53rd power minus one. There’s no specific type for integers. All numbers are floating point numbers. There’re also 3 symbolic values: Infinity , -Infinity and NaN . These are all within the range or are Infinity , -Infinity or NaN so they all have the type of 'number' . Number(‘shoe’) returns NaN and since NaN is of type number, typeof Number(‘shoe’) is number.

Strings

The following operands will return 'string' if the typeof operator is applied to it. Therefore, all of the expressions when logged will output true .

typeof '' === 'string';
typeof 'abc' === 'string';
typeof `template string` === 'string';
typeof '2' === 'string';
typeof (typeof 2) === 'string';
typeof String(1) === 'string';

Strings are used to represent textual data. Each element of the string has its own position in the string. It’s zero indexed, so the position of the first character of a string is 0. The length property of the string has the total number of characters of the string.

JavaScript strings are immutable. We cannot modify a string that has been created, but we can still create a new string that contains the originally defined string. We can extract substrings from a string with the substr() function and use the concat() function to concatenate 2 strings.

In JavaScript, anything surrounded by single quotes, double quotes, or backticks are strings. Single and double quote surround normal strings, and backticks surround template strings. The String function converts anything to a string, so String(1) returns '1' , so it’s of type string. The typeof operator returns a string, so if we are applying the typeof operator to the result returned by typeof , then that should be a string.

Booleans

The following operands will return 'boolean' if the typeof operator is applied to it. Therefore, all of the expressions when logged will output true .

typeof true === 'boolean';
typeof false === 'boolean';
typeof Boolean(2) === 'boolean';
typeof !!(2) === 'boolean';

The Boolean function and the double not operator (!! ) will both convert truthy values to true and falsy values to false . Falsy values in JavaScript includes 0, empty string, null , undefined , and false . So if they are passed in as as arguments to the Boolean function then they are converted to false . Everything else is truthy, so they’re converted to true with the Boolean function or the double not operator.

Symbols

The following operands will return 'symbol' if the typeof operator is applied to it. Therefore, all of the expressions when logged will output true .

typeof Symbol() === 'symbol'
typeof Symbol('foo') === 'symbol'
typeof Symbol.iterator === 'symbol'

Symbols are new to ES2015. It is unique and immutable identifier. Once you created it, it cannot be copied. Every time you create a new Symbol it is a unique one. It’s mainly used for unique identifiers in an object. It’s a Symbol’s only purpose.

The Symbol function creates a new symbol, so anything returned by it is of type symbol. Symbol.iterator is a special symbol, so that’s also of type symbol.

Undefined

The following operands will return 'undefined' if the typeof operator is applied to it. Therefore, all of the expressions when logged will output true .

typeof undefined === 'undefined';
typeof declaredVariableWithoutValueAssigned === 'undefined';
typeof undeclaredVariable === 'undefined';

A variable that has not been assigned a value has type undefined. If you do not assign a value to a declared variable or try to reference an undeclared variable, then you would get type undefined if you apply the typeof operator to them. Likewise, if you have never declared the property of an object or have declared the property haven’t assigned a value to it, those properties will also have the undefined type.

Objects

The following operands will return 'object' if the typeof operator is applied to it. Therefore, all of the expressions when logged will output true .

typeof {a: 1} === 'object';
typeof [1, 2, 4] === 'object';
typeof null === 'object';
typeof new Date() === 'object';
typeof /regex/ === 'object';

Object is a reference data type, which means it can be referenced by an identifier which points to location of the location of the object in memory. In memory, the object’s value is stored, and with the identifier, we can access the value. Object has properties, which are key-value pairs with the values being able to contain the data with primitive types or other objects, which means we can use object to build complex data structures.

In addition to data with key-value pairs having the type object, the null type also returns object when the typeof operator is operated on it. Arrays and other iterable objects also return object as the type when we apply the operator to it to get the type, since these kinds of data are also objects in JavaScript. To check if an object is an array, we can use the Array.isArray function to determine if an object is an array.

Functions

The following operands will return 'function' if the typeof operator is applied to it. Therefore, all of the expressions when logged will output true .

typeof function() {} === 'function';
typeof class C {} === 'function';
typeof Math.sin === 'function';

Functions are objects in JavaScript. Any kinds of functions, like arrow functions, functions declares with the function keyword, and classes are of type function. Note that classes in JavaScript is just syntactic sugar for functions that we can create new objects with. Therefore, classes are still of type function.

BigInts

The following operands will return 'bigint' if the typeof operator is applied to it. Therefore, all of the expressions when logged will output true .

typeof 42n === 'bigint';

In JavaScript, there is the BigInt type to store numbers that are beyond safe integer range. A BigInt number can be created by adding an n character to the end of a number. With BigInt, we can make calculations that have results beyond the safe range of normal numbers. So any number that ends with an n will be of type bigint .

New Operator

The new Operator will always return an object to whatever it’s applied to, so the following will always have type object. The following operands will return 'object' if the typeof operator is applied to it. Therefore, all of the expressions when logged will output true .

typeof new Boolean(true) === 'object';
typeof new Number(1) === 'object';
typeof new String('abc') === 'object';
`typeof new String(null)` === 'object';`typeof new Number(undefined)` === 'object';

Notice that no matter what we have, we get type object if the new keyword is used to create the object. It doesn’t matter whether it’s boolean, number, string, or whatever you pass in, Therefore, when we don’t need to use the new keyword to create the object, then don’t do it. To convert things to boolean, we use the Boolean function, to convert things to numbers we use the Number function, and to convert things to a string, we use the String function.

Null Type

null objects are of type object because they were represented by type tag 0. The null pointer for JavaScript is 0x00 like in most platforms. Therefore, null has type tag 0, so object has object as the type returned by typeof .

Determining Types of Expressions

We can use the typeof operator to determine the type of entities returned by expressions. We parentheses to determine the type of the result combined together in expressions. For example, if we want to get the type of 1 + ‘1’ , then we need to write:

typeof (1 + '1');

If we write the code above, we get string as the type, which is the correct type of the result of the expression. If we don’t put parentheses around the expression, then we only get the type of the first part of the expression, which is number concatenated with '1' .

Errors

Using the typeof operator before a variable declared with let or const will result in a ReferenceError being thrown, since it’s referencing a variable that’s not declared yet. Previous using the typeof operator on undeclared variables will return the type 'undefined’. The typeof operator never generated an error before ES2015.

For example, if we have:

typeof letVariable;
typeof constant;
typeof c;

let letVariable;
const constant = 'constant';
class c{};

The first 3 lines will throw a ReferenceError when they’re run.

The typeof operator is useful for checking types of primitive types and objects. For primitive types, it will return the type of the object, except for null type, which will return object as the type. Objects, including arrays and other iterable objects, will always return object as the type. With variables declared with let or const keywords and classes, we have to declare them before using the typeof operator on them.