简体   繁体   中英

IntelliSense/JSDoc @param = @return, a.k.a. how do I document wrapper functions?

I have a function which takes in another function as an argument, does something to that function-argument, and then returns that same function-argument (or at least returns a function with the exact same signature to it)

/**
 * The param and return should be the same (as far as JSDoc is concerned)!
 * @param {Function} fnToWrap
 * @returns {fnToWrap}
 */
function wrapperFunction(fnToWrap) {
    // Does something...
    return fnToWrap;
}

However, as you can see from my comments in the following...

/**
 * IntelliSense detects this...
 * @param paramA 
 * @returns 
 */
var arbitraryFn = function(paramA) {
    return paramA * 2;
}


// But NOT this!!!
var wrappedArbitraryFn = wrapperFunction(arbitraryFn);

... IntelliSense will autocomplete when calling arbitraryFn() but not wrappedArbitraryFn() .

Is there any way to get IntelliSense to dynamically autocomplete my wrapped functions with the same signature as their unwrapped counterparts, ie without having to explicitly re-document every newly-wrapped function?

I'm revisiting this again as I now have a (near-)perfect solution for my use-case. The reality is IntelliSense is far more TypeScript than it is standard JSDoc. As it turns out, you can leverage the @template tag to solve the above, and as far as I've seen, anything I can accomplish in TypeScript I can also accomplish in JavaScript IntelliSense :

The New Wrapper Function

/**
 * The param and return should be the same (as far as JSDoc is concerned)!
 * @template {Function} T
 * @param {T} fnToWrap
 * @returns {T}
 */
 function wrapperFunction(fnToWrap) {
    // Does something...
    return fnToWrap;
}

Wrapping a Previously-Declared Function

/**
 * IntelliSense detects this...
 * @param {Number} paramA 
 */
function previouslyDeclared(paramA) {
    return paramA * 2;
}

// And it also detects this!
var afterWrapping = wrapperFunction(previouslyDeclared);

Wrapping an inline Function

// And it also detects this!
var wrappedArbitraryFn = wrapperFunction(
    /**
     * IntelliSense detects this
     * @param {String} a 
     * @param {Number} b 
     * @param {Function} c 
     * @returns 
     */
    (a, b, c) => {
        return 22;
    }
);

Only downside for me is the inline is a bit ugly, imo, but it works. However, do note that this may not be a valid solution for true/vanilla JSDoc . This solution is great if, like me, you don't really use/care about JSDoc and you're really just here for the IntelliSense piece.

This isn't exactly what I'm looking for, but after posting this question I did discover this method which isn't too bad:

/**
 * @type {arbitraryFn}
 */
var wrappedArbitraryFn = wrapperFunction(arbitraryFn);

This works and isn't too tedious, however be aware of the following:

  • This requires pre-defining the original function. In other words, I can't get this to work for functions declared inside the call to the wrapper function, eg this won't work for var wrapped = wrapperFunction((a, b) => a + b)
  • This will break if you try to rename the function with the "Rename Symbol" command (F2) in Visual Studio Code unless you document the original function with an @typedef . Putting a @typedef every time might be fine, but I don't know if there are any side effects to that tag. Plus it's an extra step to remember, and one that doesn't have obvious/immediate consequences if you forget it

So I'm still very open to answers!

@user3781737 solution worked for me, after 6+ hours of debugging.

If anyone is having trouble getting props suggestions to work on components with forwarded props ie: {...props} I have found this solution using JSdoc @type annotation. It requires you have access to the props of the component where you are forwarding the props to:

import React from 'react';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import { HeaderButton, HeaderButtonProps } from 'react-navigation-header-buttons';
import PropTypes from 'prop-types';

/**
 * Used to wrap react-navigations default headerButton. 
 *
 * @type {React.FC<ButtonPropTypes & HeaderButtonProps>}
 */
const DefaultHeaderButton = props => {
    return (
        <HeaderButton 
            {...props} 
            IconComponent={MaterialCommunityIcons} 
            iconSize={30} 
            color={props.color || "#fff"}
        />
    );
};

DefaultHeaderButton.displayName = 'DefaultHeaderButton';
const ButtonPropTypes = {
    color: PropTypes.string
}
DefaultHeaderButton.propTypes = ButtonPropTypes;

export default DefaultHeaderButton;

Edit: I realized this is only necessary if the propTypes are a typescript interface while using javascript. In most cases you can just spread the original item's propTypes into your custom 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