JsDoc:如何记录一个对象可以具有任意(未知)属性,但具有特定类型的信息?

26
这与问题30360391类似。我想表达的是函数的参数是一个普通的JS对象,它可以具有任意属性(具有未知名称),但所有属性本身都是具有固定属性的对象。
例如:函数就像这样。
/**
 * @param {Descriptor} desc
 */
function foo( desc ) {
  // ...
}

一个典型的desc看起来像这样
desc = {
  unknownEntity1: {
    priority: 5,
    writable: false,
  },
  unknownEntity2: {
    priority: 42,
    writable: true,
  },
  unknownEntity3: {
    priority: 9,
    writable: false,
  }
}

我已经有了。
/**
 * @typedef {Object} DescriptorEntry
 * @property {number} priority - The priority of the entity
 * @property {boolean} writable - True, if the entity can be modified
 */

我仍然需要一个`typedef`来表示`Descriptor`,它基本上表达了`Descriptor`是一个具有任意属性但所有属性都是`DescriptorEntry`类型的对象。伪代码如下:
/**
 * @typedef {Object} Descriptor
 * @property {DescriptorEntry} *
 */

当然,星号 * 作为“任何属性”的通配符在 Jsdoc 语法中是无效的。但是我应该如何正确使用它呢?
2个回答

16

根据https://jsdoc.app/tags-type.html,从 JSDoc 3.2 开始,JSDoc 已完全支持 Google Closure 编译器类型表达式。其中一种格式在https://jsdoc.app/tags-type.html#jsdoc-types中有描述:

{Object.<string, number>}

所以在你的情况下,你应该能够做到:

/**
 * @typedef {Object.<string, DescriptorEntry>} Descriptor
 */

或者只需:

/**
 * @typedef {{string, DescriptorEntry}} Descriptor
 */

你甚至可以在上面的例子中用自己的类型替换string,如果你想要一个名为DescriptorName或类似的特殊类型来详细说明可允许的字符串值。

不过有一点需要注意,在我这个案例中,虽然JSDoc并没有拒绝这种后一种格式,但至少在默认模板下,它只显示为一个“对象”,没有任何特殊的细节。而第一种格式则能正确地显示。


截至2020.3.1版本,此功能在PHPStorm中无法正常运作。当我执行for(let key in desc)时,仍会出现“可能对自定义/继承属性进行迭代”的诊断提示。 - Szczepan Hołyszewski
1
今天,人们可以参考https://jsdoc.app/tags-type.html,因为http://usejsdoc.org/已经不存在了。 - christopher.theagen

2
这是关于PropertyDescriptorPropertyDescriptorMap的Typescript接口。(它们也被PhpStorm 2020用于代码补全): TypeScript/lib/lib.es5.d.ts
interface PropertyDescriptor {
    configurable?: boolean;
    enumerable?: boolean;
    value?: any;
    writable?: boolean;
    get?(): any;
    set?(v: any): void;
}

interface PropertyDescriptorMap {
    [s: string]: PropertyDescriptor;
}

你可以直接使用它们作为@type {},或重新定义两者:
/**
 * @typedef {Object} PropertyDescriptor
 * @property {function(v: *): void} [set]             - Set [name](v){...}      'accessor descriptor' only
 * @property {function(): *}        [get]             - Get [name](){...}       'accessor descriptor' only
 * @property {undefined|*}          [value]           - Value (primitive|func)  valid in 'data descriptor' only
 * @property {undefined|boolean}    [writable]        - Writable                valid in 'data descriptor' only
 * @property {undefined|boolean}    [configurable]    - Configurable            valid in 'data && accessor - descriptor'
 * @property {undefined|boolean}    [enumerable]      - Enumerable              valid in 'data && accessor - descriptor'
 */

/**
 * @typedef {Object<string,PropertyDescriptor>} PropertyDescriptorMap
 */

/**
 *  @type {PropertyDescriptor} myDescriptor
 */
let myDescriptor = {
    configurable: true,
    enumerable: true,
    // value: {},
    // writable: true,
    get myGet(){},
    set myGet(v){}
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接