Using JSDoc to enable intellisense for render props in vscode

strongly typed render props in vscode intellisense without typescript

Gaurav Gupta
smallcase Engineering

--

Setup

We have a react codebase where we have many React components with the render props pattern. In this codebase we haven’t enabled typescript (yet), and we generally use prop-types for dynamic type checking. We use vscode for development and take advantage of its intellisense / autocompletion in our dev workflow.

About vscode intellisense

vscode uses typescript internally, and in most cases, it can automatically infer types from type-definitions, JSDoc comments or proptypes. For function components, vscode can offer code completion suggestions by default, and if you have proptypes for the function component, it can infer the type of the props as well.

Case 1: Function component without prop destructuring, and without prop types

  • vscode shows the whole props object as any on hovering over the usage
  • vscode does not provide any autocompletion when adding props in the usage
codesandbox example for functional component without destrcuturing without prop types

Case 2: Function component without prop destructuring, with prop types

  • vscode shows the whole props object as any on hovering over the usage
  • vscode provides autocompletion hints, as well as types while adding props in the usage
vscode provides types while adding props
vscode provides autocompletion
codesandbox example for functional component without destrcuturing with prop types

Case 3: Function component with prop destructuruing and prop types

  • vscode shows the destructured props object when hovering over the usage (though the object properties are still shown as any )
  • vscode provides autocompletion hints, as well as types while adding props in the usage
vscode provides autocomplete with types in usage
codesandbox example for functional component with destrcuturing and prop types

Case 4: Class component

  • vscode is not able to infer props for Class components, with or without prop types

NOTE:

  • vscode still shows prop types as any on hover in all the cases
  • vscode shows all props as optional while hovdering as well as while autocomplete.

The problem

We will take an example of a toggle component with the render props pattern. This component calls the children function passing the open value, so that the parent can render whatever they want the toggle is open.

Although vscode can infer types from prop types in basic cases, it can’t do that effectively when the prop is a function.
This is because:

  • it is not easy to specify a strongly typed function prop using prop types. You can’t specify the function params or return type in prop types
import React, { useState } from "react";
import PropTypes from "prop-types";
// This does not work with autocomplete,
// as there is no easy way for vscode to infer
// the type of the children function
function Toggle(props) {
const [open, setOpen] = useState(false);
return (
<div>
<button type="button" onClick={() => setOpen(!open)}>
{" "}
Toggle
{" "}
</button>
{props.children({ open })}
</div>
);
}
Toggle.propTypes = {
children: PropTypes.func.isRequired
};
export default Toggle;
vscode is not able to infer the type of render props function
codesandbox example for render props with generic proptypes function check
  • when using custom validators in prop types for making sure that the prop adheres to a certain interface, vscode can’t correctly infer the function params and return types.
import React, { useState } from "react";
import PropTypes from "prop-types";
// This does not work with autocomplete,
// as there is no easy way for vscode to infer
// the type of the children function
function Toggle(props) {
const [open, setOpen] = useState(false);
return (
<div>
<button type="button" onClick={() => setOpen(!open)}>
{" "}
Toggle
{" "}
</button>
{props.children({ open })}
</div>
);
}
Toggle.propTypes = {
children: (props, propName, componentName) => {
let error;
const prop = props[propName];
if (typeof prop !== "function") {
error = new Error("expected children to be a function");
}
if (prop.length === 0) {
error = new Error("expected children to be a function with 1 argument");
}
// ...don't know how to verify further
return error;
}
};
export default Toggle;
vscode is not able to infer the type of render props function
codesandbox example for render props with proptypes custom validator function check

As you would know, children as function is the basis of the render props patten. Since we are not able to specify the prop type of the children function correctly using prop types, vscode can’t guess it and can not suggest correct types at the point of usage. This leads to a lot of to-and-fro in the usage vs definition, just to figure out what to expect from the render props children function.

The solution

Enter JSDoc. As mentioned earlier, vscode includes JSDoc comments, if available, in its type inference. So, although we can’t specify the exact type of the children function using prop types, we can still annotate it using JSDoc, and vscode would be able to suggest the types at the point of usage.

import React, { useState } from "react";
import PropTypes from "prop-types";
// This works with autocomplete,
// as vscode can infer
// the type of the children function
// based on the jsdocs
/**
* @callback ChildrenFn
* @param {{ open: boolean }} props - whether the toggle is open or not
* @returns {React.ElementType}
*/
/**
* @param {Object} props
* @param {ChildrenFn} props.children
*/
function Toggle(props) {
const [open, setOpen] = useState(false);
return (
<div>
<button type="button" onClick={() => setOpen(!open)}>
{" "}
Toggle
{" "}
</button>
{props.children({ open })}
</div>
);
}
Toggle.propTypes = {
children: PropTypes.func.isRequired
};
export default Toggle;
vscode is able to infer the type of the params in the render props children function
codesandbox example for render props with jsdoc for render props children function

References:

--

--