简体   繁体   中英

How do i annotate React.forwardRef with jsdoc comments so that intellisense can show up for the underlying component?

I have a React component written as a function this way:

function Button({ text, icon }) {
  return ...
}

Button.propTypes = {
  text: PropTypes.string.isRequired,
  icon: PropTypes.string.isRequired
}

when using this component, I get the autocompletion / intellisense in vscode

If i wrap this component in React.forwardRef, export default React.forwardRef((props, ref) => <Button btnRef={ref} {...props} />)

then I get the intellisense for the forwardRef function, which does not help my usage, because now there is no way for me to get the props autocompleted / show up in intellisense.

I have tried annotating the React.forwardRef with jsdoc extends / augments but to no success, in that case even the default intellisense for forwardRef usage stops showing up. (I believe this is because vscode gives more preference to available types than jsdoc comments). Is there a way for me to get the intellisense for the wrapped component working similar to the unwrapped component? This would be inline with the understanding that I have for using the wrapped component in a similar way as the unwrapped component.

It depends how pedantic you want to be about the types. Generally, the use of these components is pretty much the same as other functional components, so the simplest way is to just declare the type of the result to be a functional component. The trick for the props is to first create a variable for the prop types and refer to that for the generic type (or at least, I haven't found a way to make it work without that interstitial value):

/**
 * @type React.FC<ButtonPropTypes>
 */
const Button = forwardRef(({ text, icon }, ref) => (
  <button ref={ref}>{text}{icon}</button>
))

const ButtonPropTypes = {
  text: string.isRequired,
  icon: string.isRequired,
  // `ref` isn't a "real" prop, so `prop-types` will not not actually validate
  // this one, but this adds it to the intellisense list if desired. Feel
  // free to just omit it.
  ref: oneOf(shape({ current: any }), func),
}

Button.propTypes = ButtonPropTypes

If you want to be more accurate, the return type of the forwardRef is actually:

/**
 * @type React.ForwardRefRenderFunction<HTMLButtonElement, ButtonPropTypes>
 */
const Button = forwardRef(({ text, icon }, ref) => (
  <button ref={ref}>{text}{icon}</button>
))

const ButtonPropTypes = {
  text: string.isRequired,
  icon: string.isRequired,
}

Button.propTypes = ButtonPropTypes

However, the IntelliSense doesn't seem to recognize the ref prop (works fine, just isn't in the list).

The definition for the type is here: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/3423b4fc3e3da09f8acc386bc2fee6fb8f5e0880/types/react/index.d.ts#L559 The first parameter is the expected type for value that will be assigned to the ref. However, since you're not actually statically typing the ref that you would pass in anyway, you might just choose to omit that one with a ? :

/**
 * @type React.ForwardRefRenderFunction<?, ButtonPropTypes>
 */

I think what you mean about the last part is that you wouldn't have both the unwrapped and the wrapped version. That's the typical pattern, as there is no real use for keeping both. However, as an aside, you can directly refer to the propTypes value of any other component for use as a generic type such as:

/**
 * @type React.FC<UnWrappedButton.propTypes>
 */

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM