这几年,前端圈子里关于 类型系统 的讨论从来没停过。
大家熟知的 TypeScript ,几乎成了前端工程的"标配"。但与此同时,越来越多的项目开始重新关注 JSDoc + TypeScript 推导 这种更轻量的方式。
尤其是在 Svelte 官方宣布弃用 TypeScript,转而采用 JSDoc 之后,很多人开始好奇:
要回答这些问题,我们先得弄清楚,现代前端所说的 JSDoc 到底指的是什么。
很多人对 JSDoc 的第一印象,可能还停留在"写点注释,自动生成文档"的层面。
确实,最早的 JSDoc 工具就是用来做文档生成的。
但如今我们聊的 JSDoc,已经不再局限于文档,而是作为 TypeScript 官方支持的一套注释语法 ,可以直接为 JavaScript 代码提供类型信息,从而获得 IDE 智能提示、类型检查,甚至能在完全不引入 TS 的情况下,体验到类似的开发体验。 来个实际案例:
这里定义了 size 类型为
s|m|l
, 为size赋值时,会有明显的代码提示,设置其他非枚举类型,vscode会直接提示: 当然在idea也是支持的

接下来,我们就通过几个案例,来看看 JSDoc 在实际开发中能发挥哪些作用,以及如何结合 TypeScript 的推导能力,帮助我们写出更安全、更高效的 JavaScript 代码。 好问题 👍。
很多团队做 纯 JS 项目 时,不想迁移到 TS,但又想要「接近 TS 的智能提示」,这时候 JSDoc + TypeScript 类型推导 就能发挥作用。
🎈前提条件
要想获取到完整的jsdoc提示,你需要在项目jsconfig.json|tsconfig.json
,设置checkJs
为true
json
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
},
"checkJs": true, // 关键!让 VSCode 分析 JS 里的 JSDoc
"jsx": "preserve",
"jsxImportSource": "vue",
"allowJs": true,
"types": ["vite/client", "vitest/globals", "lodash", "ant-design-vue/typings/global.d.ts"]
},
"exclude": ["node_modules", "dist"]
}
这样 VSCode 会对 JS 文件里的 JSDoc 进行类型检查。
1. 对象 / 数组 类型提示
普通对象
php
// @ts-check
/**
* @typedef {Object} User
* @property {string} name
* @property {number} age
* @property {boolean} isAdmin
*/
/** @type {User} */
const user = { name: 'Tom', age: 18, isAdmin: false }
user.name // ✅ string 提示
user.age // ✅ number 提示
user.isAdmin // ✅ boolean 提示
数组
ini
/** @type {User[]} */
const users = [{ name: 'Jerry', age: 20, isAdmin: true }]
users[0].age // ✅ number 提示
2. 函数参数与返回值
php
/**
* @param {number} x
* @param {number} y
* @returns {number}
*/
function add(x, y) {
return x + y
}
add(1, 2) // ✅ number 提示
add('a', 2) // ❌ 报错(因为 @ts-check 生效)
3. 函数回调
javascript
/**
* @callback Comparator
* @param {string} a
* @param {string} b
* @returns {number}
*/
/**
* @param {string[]} arr
* @param {Comparator} compare
*/
function sortStrings(arr, compare) {
return arr.sort(compare)
}
sortStrings(['a', 'bb'], (a, b) => a.length - b.length) // ✅ a b 自动推导为 string
4. 泛型(结合 TS 推导)
php
/**
* @template T
* @param {T[]} arr
* @returns {T}
*/
function first(arr) {
return arr[0]
}
first([1, 2, 3]) // ✅ number
first(['a', 'b']) // ✅ string
first([{ id: 1 }]).id // ✅ number
5. 类 / 构造函数
kotlin
/**
* @typedef {Object} Point
* @property {number} x
* @property {number} y
*/
class Shape {
/** @param {Point} start */
constructor(start) {
this.start = start
}
/** @returns {Point} */
move() {
return { x: this.start.x + 1, y: this.start.y + 1 }
}
}
const s = new Shape({ x: 0, y: 0 })
s.move().x // ✅ number
6. 对象字典 / Map
php
/** @type {Record<string, number>} */
const scores = {
math: 100,
english: 90,
}
scores.math // ✅ number
scores.abc // ✅ number(自动提示)
7. 第三方库(axios / fetch 结果)
javascript
/**
* @typedef {Object} Todo
* @property {number} id
* @property {string} title
* @property {boolean} completed
*/
/**
* @returns {Promise<Todo[]>}
*/
async function fetchTodos() {
const res = await fetch('https://jsonplaceholder.typicode.com/todos')
return res.json()
}
fetchTodos().then(todos => {
todos[0].title // ✅ string
todos[0].completed // ✅ boolean
})
8. 前端状态管理(Pinia / Vuex 风格)
javascript
import { defineStore } from 'pinia'
export const useTestStore = defineStore('test', {
state: () => ({
/** @type {{ id: number, name: string, done: boolean }[]} */
todos: []
}),
getters: {
unfinished(state) {
return state.todos.filter(t => !t.done) // ✅ 提示 done、id、name
}
},
actions: {
/** @param {string} name */
add(name) {
this.todos.push({ id: Date.now(), name, done: false })
}
}
})
9. 工具函数库
javascript
/**
* @template T
* @param {T[]} arr
* @param {(item: T) => boolean} predicate
* @returns {T[]}
*/
function filter(arr, predicate) {
return arr.filter(predicate)
}
filter([1, 2, 3], x => x > 2) // ✅ x 推导成 number
filter(['a', 'b'], x => x === 'a') // ✅ x 推导成 string
10. Node.js 代码(Express / Koa)
php
/**
* @typedef {import('express').Request} Request
* @typedef {import('express').Response} Response
*/
/**
* @param {Request} req
* @param {Response} res
*/
function handler(req, res) {
res.json({ ok: true }) // ✅ res 自动有提示
}
⚡最佳实践总结
- 统一用 @typedef 定义对象结构,避免到处写长类型。
- 函数一定写参数和返回值类型,团队协作时减少误用。
- 工具函数优先用 @template,让 TS 自动推导。
- 前端框架结合库类型定义 (Vue/React/Express),通过
import('xxx')
引入已有的 TS 定义。 - 在团队项目里,可以把常用类型放在
types.d.ts
或types.js
中(加上 JSDoc 注解),全局复用。
这样一来,即使项目是 纯 JS ,也能获得 接近 TS 的类型安全 + 自动补全体验。
vscode代码片段分享
最后分享一份自己使用的代码片段,可快速定义jsdoc

json
{
"JSDoc Typedef Object": {
"prefix": "jsdoc-typedef",
"body": [
"/**",
" * @typedef {Object} ${1:TypeName}",
" * @property {string} ${2:prop1}",
" * @property {number} ${3:prop2}",
" * @property {boolean} ${4:prop3}",
" */"
],
"description": "定义对象类型 (typedef)"
},
"JSDoc Type Array": {
"prefix": "jsdoc-array",
"body": [
"/** @type {${1:Type}[]} */",
"const ${2:name} = [];"
],
"description": "定义数组类型"
},
"JSDoc Function Params": {
"prefix": "jsdoc-func",
"body": [
"/**",
" * @param {${1:type}} ${2:param} - ${3:描述}",
" * @param {${4:type}} ${5:param} - ${6:描述}",
" * @returns {${7:type}} - ${8:描述}",
" */",
"function ${9:fnName}(${2:param}, ${5:param}) {",
" $0",
"}"
],
"description": "函数参数与返回值注释"
},
"JSDoc Callback": {
"prefix": "jsdoc-callback",
"body": [
"/**",
" * @callback ${1:CallbackName}",
" * @param {${2:type}} ${3:param}",
" * @param {${4:type}} ${5:param}",
" * @returns {${6:type}}",
" */"
],
"description": "定义回调类型"
},
"JSDoc Generic Function": {
"prefix": "jsdoc-generic",
"body": [
"/**",
" * @template T",
" * @param {T[]} arr",
" * @returns {T}",
" */",
"function ${1:first}(arr) {",
" return arr[0]",
"}"
],
"description": "泛型函数"
},
"JSDoc Class Method": {
"prefix": "jsdoc-class",
"body": [
"class ${1:ClassName} {",
" /**",
" * @param {${2:type}} ${3:param}",
" */",
" constructor(${3:param}) {",
" this.${3:param} = ${3:param}",
" }",
"",
" /**",
" * @returns {${4:type}}",
" */",
" ${5:method}() {",
" return this.${3:param}",
" }",
"}"
],
"description": "类与方法注释"
},
"JSDoc Import Type": {
"prefix": "jsdoc-import",
"body": [
"/** @typedef {import('${1:package}').${2:Type}} ${3:Alias} */"
],
"description": "从 TS 类型定义导入类型"
}
}