Svelte邪修的JSDoc,到底是个啥?

这几年,前端圈子里关于 类型系统 的讨论从来没停过。

大家熟知的 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 自动有提示
}

⚡最佳实践总结

  1. 统一用 @typedef 定义对象结构,避免到处写长类型。
  2. 函数一定写参数和返回值类型,团队协作时减少误用。
  3. 工具函数优先用 @template,让 TS 自动推导。
  4. 前端框架结合库类型定义 (Vue/React/Express),通过 import('xxx') 引入已有的 TS 定义。
  5. 在团队项目里,可以把常用类型放在 types.d.tstypes.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 类型定义导入类型"
  }
}
相关推荐
TimelessHaze12 分钟前
🔥 一文掌握 JavaScript 数组方法(2025 全面指南):分类解析 × 业务场景 × 易错点
前端·javascript·trae
jvxiao44 分钟前
搭建个人博客系列--(4) 利用Github Actions自动构建博客
前端
袁煦丞1 小时前
SimpleMindMap私有部署团队脑力风暴:cpolar内网穿透实验室第401个成功挑战
前端·程序员·远程工作
li理1 小时前
鸿蒙 Next 布局开发实战:6 大核心布局组件全解析
前端
EndingCoder1 小时前
React 19 与 Next.js:利用最新 React 功能
前端·javascript·后端·react.js·前端框架·全栈·next.js
li理1 小时前
鸿蒙 Next 布局大师课:从像素级控制到多端适配的实战指南
前端
前端赵哈哈1 小时前
Vite 图片压缩的 4 种有效方法
前端·vue.js·vite
Nicholas681 小时前
flutter滚动视图之ScrollView源码解析(五)
前端
电商API大数据接口开发Cris1 小时前
Go 语言并发采集淘宝商品数据:利用 API 实现高性能抓取
前端·数据挖掘·api
ITMan彪叔1 小时前
Nodejs打包 Webpack 中 __dirname 的正确配置与行为解析
javascript·后端