VSCode 插件开发实战:JSON 转 TypeScript 接口 & TypeScript 接口转 Mock 数据
前端开发者的效率神器,手把手教你开发属于自己的 VSCode 插件
一、前言
1.1 为什么要开发这个插件?
在前端日常开发中,我们经常遇到以下场景:
- 后端返回 JSON 数据,需要手动编写对应的 TypeScript 接口 - 繁琐且容易出错
- 编写单元测试时,需要手动编写 Mock 数据 - 耗时且数据不够真实
- 前后端接口对接时,需要频繁转换数据格式 - 效率低下
- 最重要的一点是:点亮这个VSCode 插件开发技术栈
为了解决这些痛点,我开发了 JSON TS Mock Helper 插件,提供两个核心功能:
- JSON 一键生成 TypeScript 接口 - 选中 JSON 文本,自动生成 TypeScript 类型定义
- TypeScript 接口一键生成 Mock 数据 - 选中 TypeScript 接口定义,自动生成真实的中文 Mock 数据
1.2 插件效果预览
// 选中以下 JSON:
{"name": "张三", "age": 25, "email": "test@example.com"}
// 一键生成 TypeScript 接口:
interface RootObject {
name: string;
age: number;
email: string;
}
// 选中以下 TypeScript 接口:
interface User {
name: string;
age: number;
email?: string;
}
// 一键生成 Mock 数据:
const mockUser = {
name: "李四",
age: 28,
email: "sample_k9f2"
};
1.3 技术栈
- TypeScript - 开发语言
- VSCode API - 插件核心能力
- quicktype-core - JSON 转 TypeScript 的核心库
- Node.js - 运行时环境
二、环境准备
2.1 开发环境要求
在开始开发之前,你需要准备以下环境:
| 工具 | 版本要求 | 说明 |
|---|---|---|
| Node.js | >= 16.x | 建议使用 LTS 版本 |
| npm | >= 8.x | Node.js 自带 |
| VSCode | >= 1.80.0 | 用于开发和调试 |
| TypeScript | >= 5.0.0 | 项目依赖 |
可以通过以下命令检查当前环境:
node --version # Node.js 版本
npm --version # npm 版本
code --version # VSCode 版本
2.2 安装 VSCode 扩展开发工具
VSCode 提供了官方的扩展开发模板,可以快速创建新项目。确保 VSCode 已安装,然后创建一个新文件夹作为工作目录:
mkdir vscode-plugin-demo
cd vscode-plugin-demo
三、项目初始化
3.1 使用官方脚手架创建项目
VSCode 官方提供了 yo code 脚手架来快速创建插件项目。在终端中运行:
npm install -g yo generator-code
yo code
按照提示选择以下选项:
? What type of extension do you want to create? New Extension (TypeScript)
? What's the name of your extension? json-ts-mock-helper
? What's the identifier of your extension? json-ts-mock-helper
? What's the description of your extension? Convert JSON to TypeScript and generate mock data
? Initialize a git repo? Yes
? Which package manager to use? npm
3.2 项目结构
创建完成后的项目结构如下:
json-ts-mock-helper/
├── src/
│ └── extension.ts # 插件入口文件
├── .vscode/
│ └── launch.json # 调试配置
├── node_modules/ # 依赖目录
├── package.json # 插件配置
├── tsconfig.json # TypeScript 配置
└── README.md # 说明文档
3.3 安装核心依赖
本插件使用 quicktype-core 来实现 JSON 到 TypeScript 的转换:
cd json-ts-mock-helper
npm install quicktype-core
quicktype-core 是一个强大的库,可以从 JSON、JSON Schema 等多种格式自动推断并生成 TypeScript、Go、Java、C# 等多种语言的类型定义。
四、核心功能实现
4.1 功能一:JSON 转 TypeScript 接口
4.1.1 实现思路
- 获取用户选中的 JSON 文本
- 使用
quicktype-core库进行类型推断 - 将生成的 TypeScript 代码插入到编辑器中
4.1.2 代码实现
创建 src/jsonToTs.ts 文件:
import { jsonInputForTargetLanguage, quicktype, InputData } from 'quicktype-core';
/**
* 将 JSON 字符串转换为 TypeScript 接口
* @param jsonString 用户选中的 JSON 文本
* @returns 生成的 TypeScript 代码
*/
export async function convertJsonToTs(jsonString: string): Promise<string> {
// 1. 验证 JSON 格式
try {
JSON.parse(jsonString);
} catch (error) {
throw new Error('Invalid JSON format. Please check your JSON syntax.');
}
// 2. 使用 quicktype 生成 TypeScript
const jsonInput = jsonInputForTargetLanguage('typescript');
await jsonInput.addSource({ name: 'RootObject', samples: [jsonString] });
const inputData = new InputData();
inputData.addInput(jsonInput);
const result = await quicktype({
inputData,
lang: 'typescript',
});
return result.lines.join('\n');
}
4.1.3 功能测试
假设我们有如下 JSON 数据:
{
"name": "张三",
"age": 25,
"email": "zhangsan@example.com",
"address": {
"city": "北京",
"country": "中国"
},
"friends": ["李四", "王五", "赵六"]
}
运行插件后,会生成如下 TypeScript 接口:
interface RootObject {
name: string;
age: number;
email: string;
address: Address;
friends: string[];
}
interface Address {
city: string;
country: string;
}
4.2 功能二:TypeScript 接口转 Mock 数据
4.2.1 实现思路
- 解析用户选中的 TypeScript 接口定义
- 根据字段类型生成对应的 Mock 数据
- 支持嵌套对象、数组、枚举等复杂类型
- 生成中文的 Mock 数据(姓名、城市、地址等)
4.2.2 代码实现
创建 src/tsToMock.ts 文件。首先定义一些 Mock 数据生成函数:
// 中文 Mock 数据源
const chineseSurnames = ['张', '李', '王', '刘', '陈', '杨', '黄', '赵', '吴', '周'];
const chineseNames = ['伟', '芳', '娜', '秀英', '敏', '静', '丽', '强', '磊', '军'];
const cities = ['北京', '上海', '广州', '深圳', '杭州', '南京', '成都', '重庆', '武汉', '西安'];
const streets = ['人民路', '中山路', '建设路', '解放路', '和平路'];
然后实现接口解析和 Mock 数据生成的核心逻辑:
interface TypeInfo {
type: string;
isOptional: boolean;
arrayType?: string;
enumValues?: string[];
}
/**
* 解析 TypeScript 接口定义
*/
function parseInterface(interfaceText: string): Map<string, Map<string, TypeInfo>> {
const interfaces = new Map<string, Map<string, TypeInfo>>();
// 匹配 interface 定义
const interfaceRegex = /interface\s+(\w+)\s*\{([^}]+)\}/g;
let match;
while ((match = interfaceRegex.exec(interfaceText)) !== null) {
const interfaceName = match[1];
const body = match[2];
const fields = new Map<string, TypeInfo>();
// 匹配字段定义
const fieldRegex = /(\w+)(\??)\s*:\s*([^;]+);/g;
let fieldMatch;
while ((fieldMatch = fieldRegex.exec(body)) !== null) {
const fieldName = fieldMatch[1];
const isOptional = fieldMatch[2] === '?';
const fieldType = fieldMatch[3].trim();
fields.set(fieldName, parseType(fieldType));
}
interfaces.set(interfaceName, fields);
}
return interfaces;
}
/**
* 根据字段类型生成 Mock 数据
*/
function generateValue(typeInfo: TypeInfo, interfaceMap: Map<string, Map<string, TypeInfo>>): unknown {
const { type, isOptional } = typeInfo;
// 30% 概率跳过可选字段
if (isOptional && Math.random() > 0.7) {
return undefined;
}
switch (type) {
case 'string':
return generateChineseName();
case 'number':
case 'Number':
return Math.floor(Math.random() * 100) + 1;
case 'boolean':
case 'Boolean':
return Math.random() > 0.5;
case 'enum':
return typeInfo.enumValues?.[0] || 'value';
default:
// 嵌套对象
if (interfaceMap.has(type)) {
return generateObject(type, interfaceMap);
}
return null;
}
}
/**
* 生成中文姓名
*/
function generateChineseName(): string {
const surname = chineseSurnames[Math.floor(Math.random() * chineseSurnames.length)];
const name = chineseNames[Math.floor(Math.random() * chineseNames.length)];
return surname + name;
}
/**
* 从 TypeScript 接口生成 Mock 数据
*/
export async function generateMockFromTs(tsCode: string): Promise<string> {
const interfaceMap = parseInterface(tsCode);
if (interfaceMap.size === 0) {
throw new Error('No valid TypeScript interface found.');
}
const firstInterface = interfaceMap.keys().next().value;
const mockData = generateObject(firstInterface, interfaceMap);
return `// Generated Mock Data\nconst mock${firstInterface} = ${JSON.stringify(mockData, null, 2)};`;
}
4.2.3 功能测试
假设我们有如下 TypeScript 接口:
interface User {
name: string;
age: number;
email?: string;
address: Address;
friends: string[];
}
interface Address {
city: string;
country: string;
}
运行插件后,会生成如下 Mock 数据:
const mockUser = {
name: "李四",
age: 32,
address: {
city: "上海",
country: "中国"
},
friends: ["王五", "赵六", "孙七"]
};
五、命令注册与快捷键
5.1 修改 package.json
在 package.json 中添加命令定义和快捷键配置:
{
"name": "json-ts-mock-helper",
"displayName": "JSON TS Mock Helper",
"contributes": {
"commands": [
{
"command": "json-ts-mock-helper.convertJsonToTs",
"title": "JSON to TS: Convert JSON to TypeScript Interface"
},
{
"command": "json-ts-mock-helper.generateMockFromTs",
"title": "JSON to TS: Generate Mock from TypeScript Interface"
}
],
"keybindings": [
{
"command": "json-ts-mock-helper.convertJsonToTs",
"key": "cmd+shift+j",
"when": "editorTextFocus"
},
{
"command": "json-ts-mock-helper.generateMockFromTs",
"key": "cmd+shift+m",
"when": "editorTextFocus"
}
]
}
}
5.2 在 extension.ts 中注册命令
修改 src/extension.ts,注册两个命令:
import * as vscode from 'vscode';
import { convertJsonToTs } from './jsonToTs';
import { generateMockFromTs } from './tsToMock';
export function activate(context: vscode.ExtensionContext) {
// 命令1: JSON 转 TypeScript
const convertJsonToTsCommand = vscode.commands.registerCommand(
'json-ts-mock-helper.convertJsonToTs',
async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showErrorMessage('No active editor found');
return;
}
const selection = editor.selection;
const selectedText = editor.document.getText(selection);
if (!selectedText || selectedText.trim() === '') {
vscode.window.showErrorMessage('Please select JSON text first');
return;
}
try {
const tsCode = await convertJsonToTs(selectedText);
if (tsCode) {
await editor.edit(editBuilder => {
editBuilder.insert(selection.end, '\n\n' + tsCode);
});
vscode.window.showInformationMessage('TypeScript interface generated!');
}
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error';
vscode.window.showErrorMessage(`Error: ${message}`);
}
}
);
// 命令2: TypeScript 转 Mock
const generateMockFromTsCommand = vscode.commands.registerCommand(
'json-ts-mock-helper.generateMockFromTs',
async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showErrorMessage('No active editor found');
return;
}
const selection = editor.selection;
const selectedText = editor.document.getText(selection);
if (!selectedText || selectedText.trim() === '') {
vscode.window.showErrorMessage('Please select TypeScript interface first');
return;
}
try {
const mockCode = await generateMockFromTs(selectedText);
if (mockCode) {
await editor.edit(editBuilder => {
editBuilder.insert(selection.end, '\n\n' + mockCode);
});
vscode.window.showInformationMessage('Mock data generated!');
}
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error';
vscode.window.showErrorMessage(`Error: ${message}`);
}
}
);
context.subscriptions.push(convertJsonToTsCommand);
context.subscriptions.push(generateMockFromTsCommand);
}
export function deactivate() {}
六、调试与运行
6.1 本地调试
- 打开 VSCode,按
F5或点击左侧调试图标 - 选择 "Debug VSCode Extension"
- 会弹出一个新的 VSCode 窗口(扩展开发主机)
- 在新窗口中:
- 创建一个
.json文件,粘贴一段 JSON - 选中 JSON 文本,按
Cmd+Shift+J测试 JSON→TS 功能 - 创建一个
.ts文件,粘贴一段 TypeScript 接口定义 - 选中接口文本,按
Cmd+Shift+M测试 TS→Mock 功能
- 创建一个
6.2 查看日志
在调试控制台可以看到插件的运行日志,有助于排查问题。
6.3 常见问题
| 问题 | 解决方案 |
|---|---|
| 快捷键不生效 | 检查 package.json 中 keybindings 配置 |
| 命令找不到 | 检查 activationEvents 是否正确注册 |
| JSON 解析错误 | 确保选中的是有效的 JSON 格式 |
| 类型生成失败 | 检查 quicktype-core 是否正确安装 |
七、打包与发布
7.1 安装打包工具
npm install -g @vscode/vsce
7.2 打包为 .vsix 文件
# 进入项目目录
cd json-ts-mock-helper
# 编译 TypeScript
npm run compile
# 打包
vsce package
打包完成后,会生成一个 .vsix 文件,可以直接拖拽到 VSCode 中安装。
7.3 发布到 VSCode 市场
- 登录 VSCode Market(需要 Microsoft 账号)
- 创建一个发布配置文件
- 使用
vsce publish命令发布
vsce publish
7.4 本地安装使用
如果你不想发布到市场,也可以直接分发 .vsix 文件:
- 打开 VSCode
- 选择 "Extensions" → "Install from VSIX"
- 选择生成的
.vsix文件
八、总结与展望
8.1 项目收获
通过这个插件的开发,我们学习到了:
- ✅ VSCode 插件项目的创建与初始化
- ✅ 使用
quicktype-core进行类型推断 - ✅ VSCode API 的使用(Editor、Selection、Commands)
- ✅ 命令注册与快捷键配置
- ✅ 插件的调试与打包发布
8.2 后续优化方向
这个插件还有很大的优化空间,欢迎大家一起参与贡献:
- 支持更多数据类型(Date、UUID、URL 等)
- 支持自定义 Mock 数据规则
- 支持生成 JSON Schema
- 支持更多目标语言(Java、Go、C# 等)
- 添加 i18n 支持
8.3 参考资料
九、代码仓库
完整代码已开源到 GitHub,欢迎 Star、Fork 和贡献!
🔗 GitHub: github.com/qqq40837095…
如果你觉得这个插件对你有帮助,请给个 Star 鼓励一下!也欢迎提交 Issue 和 Pull Request 一起完善这个项目。
首发于 掘金 作者:前端从业猿 链接:juejin.cn/user/412364…