方法简写JSDoc保留Skill method-shorthand-jsdoc

这个技能用于在TypeScript或JavaScript开发中,通过工厂函数返回对象时使用方法简写,确保JSDoc注释在IDE中可见,提高代码文档的可读性和维护性。关键词:JSDoc、TypeScript、JavaScript、工厂函数、方法简写、代码文档、IDE提示、前端开发。

前端开发 0 次安装 0 次浏览 更新于 3/20/2026

name: method-shorthand-jsdoc description: 使用方法简写将辅助函数移入返回对象,以正确保留JSDoc。适用于工厂函数有内部辅助函数时,这些函数应暴露文档给消费者,或当悬停在返回的方法上不显示JSDoc时。 metadata: author: epicenter version: ‘1.0’

方法简写用于JSDoc保留

当工厂函数有仅由返回方法使用的辅助函数时,使用方法简写将它们移到返回对象中。这确保JSDoc注释正确传递给消费者。

问题

你编写一个带有文档齐全的辅助函数的工厂函数:

function createHeadDoc(options: { workspaceId: string }) {
	const { workspaceId } = options;

	/**
	 * 获取当前纪元号。
	 *
	 * 计算所有客户端提议纪元的最大值。
	 * 这确保并发碰撞收敛到相同版本。
	 *
	 * @returns 当前纪元(如果没有碰撞发生,则为0)
	 */
	function getEpoch(): number {
		let max = 0;
		for (const value of epochsMap.values()) {
			max = Math.max(max, value);
		}
		return max;
	}

	return {
		workspaceId,
		getEpoch, // JSDoc在悬停在返回对象上时不可见!

		bumpEpoch(): number {
			const next = getEpoch() + 1; // 调用内部辅助函数
			return next;
		},
	};
}

当你在IDE中悬停在head.getEpoch()上时,你看到…什么都没有。JSDoc丢失了。

解决方案

使用方法简写将辅助函数移到返回对象中:

function createHeadDoc(options: { workspaceId: string }) {
	const { workspaceId } = options;

	return {
		workspaceId,

		/**
		 * 获取当前纪元号。
		 *
		 * 计算所有客户端提议纪元的最大值。
		 * 这确保并发碰撞收敛到相同版本。
		 *
		 * @returns 当前纪元(如果没有碰撞发生,则为0)
		 */
		getEpoch(): number {
			let max = 0;
			for (const value of epochsMap.values()) {
				max = Math.max(max, value);
			}
			return max;
		},

		bumpEpoch(): number {
			const next = this.getEpoch() + 1; // 使用this.methodName()
			return next;
		},
	};
}

现在悬停在head.getEpoch()上显示完整的JSDoc。

为什么这有效

  1. JSDoc附加到方法定义位置 - 当方法在返回对象中内联定义时,JSDoc直接附加到TypeScript看到的属性上
  2. 方法简写使用function语义 - this绑定到对象,所以this.getEpoch()有效
  3. 无需单独辅助函数 - 如果仅由兄弟方法使用,它属于同一对象

模式

// 错误:辅助函数单独定义,JSDoc在返回时丢失
function createService(client) {
  /** 使用缓存获取用户数据。 */
  function fetchUser(id: string) { ... }

  return {
    fetchUser,  // JSDoc对消费者不可见!
    getProfile(id: string) {
      return fetchUser(id);  // 工作,但消费者看不到文档
    },
  };
}

// 正确:方法简写,JSDoc保留
function createService(client) {
  return {
    /** 使用缓存获取用户数据。 */
    fetchUser(id: string) { ... },

    getProfile(id: string) {
      return this.fetchUser(id);  // 使用this.method()
    },
  };
}

何时应用

在以下情况使用此模式:

  • 辅助函数仅由返回对象中的方法使用
  • 你希望消费者悬停在方法上时看到JSDoc
  • 辅助函数在返回语句之前不需要被调用

在以下情况保持辅助函数单独:

  • 它们在初始化期间被调用(在返回之前)
  • 它们由多个工厂函数使用(提取到共享模块)
  • 它们真正是内部的,不应暴露

箭头函数无效

箭头函数没有自己的this

// 错误:箭头函数,this未定义
return {
  getEpoch: () => { ... },
  bumpEpoch: () => {
    this.getEpoch();  // 错误:this未定义!
  },
};

// 正确:方法简写有正确的this绑定
return {
  getEpoch() { ... },
  bumpEpoch() {
    this.getEpoch();  // 工作!
  },
};

真实示例

来自packages/epicenter/src/core/docs/head-doc.ts

export function createHeadDoc(options: { workspaceId: string; ydoc?: Y.Doc }) {
	const { workspaceId } = options;
	const ydoc = options.ydoc ?? new Y.Doc({ guid: workspaceId });
	const epochsMap = ydoc.getMap<number>('epochs');

	return {
		ydoc,
		workspaceId,

		/**
		 * 获取当前纪元号。
		 *
		 * 计算所有客户端提议纪元的最大值。
		 * 这确保并发碰撞收敛到相同版本
		 * 而不跳过纪元号。
		 *
		 * @returns 当前纪元(如果没有碰撞发生,则为0)
		 */
		getEpoch(): number {
			let max = 0;
			for (const value of epochsMap.values()) {
				max = Math.max(max, value);
			}
			return max;
		},

		/**
		 * 碰撞纪元到下一个版本。
		 *
		 * @returns 碰撞后的新纪元号
		 */
		bumpEpoch(): number {
			const next = this.getEpoch() + 1;
			epochsMap.set(ydoc.clientID.toString(), next);
			return next;
		},

		// ... 其他使用this.getEpoch()的方法
	};
}

总结

方法 JSDoc可见? this有效?
单独辅助函数 + 引用 不适用
返回对象中的箭头函数
返回对象中的方法简写

方法简写是唯一保留JSDoc并允许方法通过this相互调用的方法。

参考文献