【问题标题】:JSDoc Include All Properties from Another @typedef ObjectJSDoc 包含来自另一个 @typedef 对象的所有属性
【发布时间】:2022-02-21 11:39:11
【问题描述】:

如果我使用 JSDoc 创建两个对象,其中一个具有另一个的所有属性,我该如何显示?

例如你有:

/** 
 * @typdef Foo
 * @type {Object}
 * @property {string} bar
 * @property {string} baz
 */

/**
 * @typedef Foobar
 * @type {Object}
 * @property {float} value
 * @property {string} bar
 * @property {string} baz
 */

但我不想写两次 bar/baz 我只想继承它。

【问题讨论】:

    标签: javascript jsdoc


    【解决方案1】:

    我相信你会这样做......

    /** Type definition for Foo.
     * @typedef {Object} Foo
     * @property {string} bar
     * @property {string} baz
     */
    
    /** Type definition for Foobar.
     * @typedef {Foo} Foobar
     * @property {float} value
     */
    

    注意Foobar 如何“继承”Foo

    【讨论】:

    • 复制粘贴您的示例。 VSCode 报告:type Foobar = { bar: string; baz: string; }
    • @JakeDK 见TypeScript feature request #20077(在 VS Code 中使用 TypeScript 解析 JSDoc。)
    【解决方案2】:

    您可以制作一个简单的 jsdoc 插件来制作它,以便您可以在 typedef 上使用 @augments/@extends。例如,可以在here 找到这样的插件(如下所示):

    /**
     * Define a jsdoc plugin to update typedefs that use augments.
     */
    exports.handlers = {
      /**
       * Modify typedefs that use augments (extends).  Add the base typedef's
       * properties to the augmented typedefs.
       */
      parseComplete: function (e) {
        var typedefs = {},
            augmentedTypedefs = {},
            numAugmented = 0;
        /* Make a dictionary of all known typedefs and a dictionary of augmented
         * typedefs */
        e.doclets.forEach(function (doclet) {
          if (doclet.kind === 'typedef') {
            typedefs[doclet.longname] = doclet;
            if (doclet.augments && doclet.augments.length) {
              augmentedTypedefs[doclet.longname] = doclet;
            }
          }
        });
        while (Object.keys(augmentedTypedefs).length !== numAugmented) {
          numAugmented = Object.keys(augmentedTypedefs).length;
          Object.keys(augmentedTypedefs).forEach(function (name) {
            var doclet = augmentedTypedefs[name];
            /* If this typedef is augmented by an augmented typedef, skip it for
             * now.  Ignore self references */
            if (doclet.augments.some(function (augmentName) {
              return augmentName !== name && augmentedTypedefs[augmentName];
            })) {
              return;
            }
            /* Ensure we have properties */
            doclet.properties = doclet.properties || [];
            /* Make a dictionary so we don't clobber known properties. */
            var properties = {};
            doclet.properties.forEach(function (prop) {
              properties[prop.name] = prop;
            });
            /* For each augment base, add its properties if we don't already have
             * them.  If the typedef augments two other typedefs that each have a
             * property of the same name, the last listed will be shown (done by
             * reversing the augments list). */
            doclet.augments.slice().reverse().forEach(function (augmentName) {
              if (augmentName !== name && typedefs[augmentName] && typedefs[augmentName].properties) {
                typedefs[augmentName].properties.forEach(function (prop) {
                  if (!properties[prop.name]) {
                    /* Make a copy so we don't mutate the original property. */
                    prop = Object.assign(prop);
                    /* Add a value that a rendering template could use to show that
                     * the property was inherted from a parent.  Since that in turn
                     * could have been inherited, preserve a known value. */
                    prop.inherited = prop.inherited || augmentName;
                    /* Add the property to the typedef and to the list of known
                     * properties. */
                    doclet.properties.push(prop);
                    properties[prop.name] = prop;
                  }
                });
              }
            });
            /* We've finished processing this typedef, so remove it from the
             * augmented list. */
            delete augmentedTypedefs[name];
          });
        }
      }
    };
    

    此时,你可以这样做:

    /** 
     * @typdef Foo
     * @type {Object}
     * @property {string} bar
     * @property {string} baz
     */
    
    /**
     * @typedef Foobar
     * @type {Object}
     * @augments Foo
     * @property {float} value
     */
    

    如果您愿意,您可以修改您的模板以显示与非继承属性不同的继承属性 (see an example):

    【讨论】:

    • 很好的例子!一个小的改进:而不是javascript prop.inherited = prop.inherited || augmentName; ,最好使用javascript prop.inherited = true; prop.inherits = prop.inherits || augmentName;
    • ... 和javascript prop = Object.assign(prop); 应该改成javascript prop = Object.assign({}, prop);
    【解决方案3】:

    这在 VSCode 中有效,不确定它有多理想。

    /**
     * @typedef {Object} Person
     * @property {string} firstName
     * @property {string} lastName
     * @property {number} age
     */
    
    /**
     * @typedef {Object} BaseUser
     * @property {string} username
     */
    
    /**
     * @typedef {Person & BaseUser} User
     */
    

    用户现在对PersonBaseUser 的所有属性都有智能感知

    【讨论】:

      最近更新 更多