Skip to content
JSDoc KubeJS ProbeJS

KubeJS/ProbeJS 场景下的 JSDoc 实践

@typedef 在自定义全局数据结构

js
/**
 * @typedef {Object} CustomRecipe
 * @property {string} id
 * @property {string[]} ingredients
 * @property {string} result
 */
/** @type {CustomRecipe} */
const recipe = {
  id: 'my:super_recipe',
  ingredients: ['minecraft:diamond', 'minecraft:stick'],
  result: 'my:super_sword'
};

@enum 用于常量集

js
/**
 * @enum {string}
 */
const ToolTier = {
  WOOD: 'wood',
  IRON: 'iron',
  DIAMOND: 'diamond'
};
// 用于物品注册
ServerEvents.registry('item', event => {
  event.create('my_pickaxe', 'pickaxe').tier(ToolTier.DIAMOND);
});

@callback 用于回调类型

js
/**
 * @callback ItemFilter
 * @param {Internal.ItemStack} stack
 * @returns {boolean}
 */
/** @type {ItemFilter} */
const isDiamond = stack => stack.id === 'minecraft:diamond';

@template 泛型函数

js
/**
 * @template T
 * @param {T[]} arr
 * @returns {T}
 */
function first(arr) { return arr[0]; }

@deprecated 标记废弃 API

js
/**
 * @deprecated 请使用 newRegisterItem 替代
 */
function oldRegisterItem() {}

@event 标注自定义事件

js
/**
 * @event CustomEvent
 * @property {Internal.Player} player
 * @property {string} message
 */
// 用于文档和类型补全

@throws 标注异常

js
/**
 * @throws {Error} 当物品不存在时抛出
 */
function getItemOrThrow(id) {
  const item = Item.of(id);
  if (!item) throw new Error('Item not found');
  return item;
}

@see 交叉引用

js
/**
 * @see https://jsdoc.app/
 * @see KubeJS/ProbeJS 类型文件
 */

@readonly 只读属性

js
/** @readonly */
const VERSION = '1.0.0';

@default 默认参数

js
/**
 * @param {string} [name="Steve"]
 * 尽管KubeJS不支持Default,JsDoc并不参与代码的运行,所以不会报错。
 * 可用作规范
 */
function greet(name) {}

@private 私有方法

js
/** @private */
function _internalHelper() {}

@public 公共方法

js
/** @public */
function registerGlobalEvent() {}

@todo 待办事项

js
/** @todo 支持更多物品类型 */
function registerSpecialItems() {}

@example 代码示例

js
/**
 * @example
 * addCustomRecipe('my:super_recipe', ['minecraft:diamond'], 'my:super_sword');
 */
function addCustomRecipe(id, ingredients, result) {}

@summary/@description/@author/@since/@license

js
/**
 * @summary 注册自定义物品
 * @description 该函数用于批量注册自定义物品,支持多种类型。
 * @author Crychic
 * @since 2024-01-01
 * @license MIT
 */
function registerItems() {}

事件参数类型提升

js
ItemEvents.entityInteracted(event => {
  event.entity.potionEffects.add('minecraft:night_vision', 200, 0, false, true); // 可能无补全
});
js
ItemEvents.entityInteracted(event => {
  /** @type {Internal.LivingEntity} */
  const living = event.entity;
  living.potionEffects.add('minecraft:night_vision', 200, 0, false, true); // 有补全
});
js
BlockEvents.broken(event => {
  /** @type {Internal.Player} */
  const player = event.player;
  player.tell('Block broken!');
});
js
PlayerEvents.chat(event => {
  /** @type {Internal.Player} */
  const player = event.player;
  player.tell('You said: ' + event.message);
});
js
ServerEvents.recipes(/** @param {Internal.RecipesEventJS} event */ event => {
  event.addShaped('minecraft:diamond', [
    'AAA',
    'AAA',
    'AAA'
  ], {
    A: 'minecraft:coal'
  });
});
js
FTBTeamsEvents.playerJoinedParty(event => {
  /** @type {Internal.Player} */
  const player = event.player;
  player.tell('Welcome to the party!');
});

注册事件与 Tag/Registry 操作类型注释

js
ServerEvents.recipes(/** @param {Internal.RecipesEventJS} event */ event => {
  // event.addShaped(...)
});
js
ServerEvents.tags('item', /** @param {TagEvent.Item} event */ event => {
  event.add('forge:ingots/iron', [
    'minecraft:iron_ingot',
    'minecraft:raw_iron'
  ]);
});
js
ServerEvents.tags('block', /** @param {TagEvent.Block} event */ event => {
  if (global.isModLoaded('some_mod')) {
    event.add('forge:ores/special', 'some_mod:special_ore');
  }
});
js
ServerEvents.registry('item', /** @param {Registry.Item} event */ event => {
  ['my_item1', 'my_item2'].forEach(id => {
    event.create(id, 'basic');
  });
});

  • 事件参数类型提升时,确保类型与实际对象兼容,否则补全虽有但运行时报错。
  • Tag/Registry 操作建议用 JSDoc 明确类型,便于多人协作和后期维护。
  • 动态 Snippet/Special 类型需唯一命名,避免与内置类型冲突。
  • 类型文件变更后需 /probejs dump 并重启 VSCode。
  • 善用类型文件和 ProbeJS Wiki 查找、反查类型定义。