1. React vs Vue 框架对比
问题: React 和 Vue 在设计思路上有什么本质的区别?
详细答案:
- 数据绑定机制:
- Vue:采用双向数据绑定,通过
v-model实现表单元素与数据的自动同步 - React:单向数据流,数据通过 props 向下传递,事件通过回调向上传递
- Vue:采用双向数据绑定,通过
- 模板语法:
- Vue:基于 HTML 的模板语法,学习成本低,支持指令(v-if、v-for)
- React:JSX 语法,JavaScript 和 HTML 混合,更灵活但需要学习成本
- 响应式系统:
- Vue 2:基于 Object.defineProperty,Vue 3:基于 Proxy
- React:通过 setState 或 useState 手动触发更新
- 组件通信:
- Vue:props/emit、provide/inject、Vuex
- React:props/callback、Context API、Redux
2. React Key 的作用机制
问题: React 里的 key 有什么用?为什么不能用 index 作为 key?
详细答案:
- Diff 算法中的作用:
- React 使用 key 来识别哪些列表项发生了变化
- 在 reconciliation 过程中,React 会比较新旧虚拟 DOM 树
- key 帮助 React 快速定位相同的元素,避免不必要的重新创建
- index 作为 key 的问题:
// 错误示例 {items.map((item, index) => ( <Item key={index} data={item} /> ))} // 当删除第一个元素时,所有元素的 index 都会改变 // 导致 React 认为所有元素都发生了变化 - 正确的 key 选择:
// 正确示例 {items.map(item => ( <Item key={item.id} data={item} /> ))} - 性能影响:使用稳定的 key 可以避免不必要的 DOM 操作,提升渲染性能
3. React Hooks 实现原理
问题: React Hooks 和 Class 组件相比,解决了什么问题?它的实现原理是什么?
详细答案:
- 解决的核心问题:
- 逻辑复用困难:HOC 和 render props 会导致组件嵌套地狱
- 复杂组件难以理解:生命周期方法中混合了不相关的逻辑
- this 指向问题:需要手动绑定 this
- 实现原理:
// 用于记录当前 hook 的索引(类似 React 中的 hook 调用顺序)
let hookIndex = 0;
// 用来存储所有 hook 的值(每次渲染后保持状态)
let hooks = [];
/**
* 自定义 useState 实现
* @param {*} initialValue - 初始状态值
* @returns [state, setState] - 返回当前状态值和更新状态的函数
*/
function useState(initialValue) {
// 保存当前这个 useState 调用的索引
const currentIndex = hookIndex;
// 如果这个索引位置还没有值,就使用初始值;否则使用已有的值(保持状态)
hooks[currentIndex] = hooks[currentIndex] || initialValue;
// 定义更新状态的函数
const setState = (newValue) => {
// 更新这个索引位置的状态值
hooks[currentIndex] = newValue;
// 触发重新渲染(模拟 React 的更新机制)
render();
};
// 使用完一个 hook 后索引递增,给下一个 hook 使用
hookIndex++;
// 返回当前状态值和更新函数
return [hooks[currentIndex], setState];
}
- Fiber 架构中的 Hooks:
- 每个 Fiber 节点都有一个 memoizedState 属性
- Hooks 以链表形式存储在 memoizedState 中
- 通过调用顺序来维护 Hook 的对应关系
4. Event Loop 详细机制
问题: 浏览器的 Event Loop 机制,宏任务和微任务的执行顺序是怎样的?
详细答案:
- 执行栈和任务队列:
console.log('1'); // 同步任务 setTimeout(() => { console.log('2'); // 宏任务 }, 0); Promise.resolve().then(() => { console.log('3'); // 微任务 }); console.log('4'); // 同步任务 // 输出顺序:1, 4, 3, 2 - 详细执行流程:
- 执行同步代码,遇到异步任务放入对应队列
- 同步代码执行完毕,检查微任务队列
- 执行所有微任务,直到微任务队列为空
- 执行一个宏任务
- 重复步骤 2-4
- 微任务类型:
- Promise.then/catch/finally
- queueMicrotask
- MutationObserver
- process.nextTick (Node.js)
- 宏任务类型:
- setTimeout/setInterval
- I/O 操作
- UI 渲染
- MessageChannel
5. CSS Position 定位详解
问题: CSS 中,position 有哪些值?它们分别是根据什么定位的?
详细答案:
- static(默认值):
- 元素按照正常文档流排列
- top、right、bottom、left 属性无效
- relative(相对定位):
- 相对于元素在正常文档流中的位置进行偏移
- 不脱离文档流,原来的空间仍然保留
.relative { position: relative; top: 10px; /* 向下偏移 10px */ left: 20px; /* 向右偏移 20px */ } - absolute(绝对定位):
- 相对于最近的非 static 定位祖先元素
- 脱离文档流,不占据原来的空间
- 如果没有定位祖先,则相对于初始包含块(通常是 viewport)
- fixed(固定定位):
- 相对于视口(viewport)定位
- 脱离文档流,滚动时位置不变
- sticky(粘性定位):
- 结合了 relative 和 fixed 的特性
- 在滚动到指定位置前表现为 relative
- 滚动到指定位置后表现为 fixed
6. Webpack vs Vite 深度对比
问题: Webpack 和 Vite 有什么区别?为什么 Vite 的开发环境启动速度会快很多?
详细答案:
- 构建原理差异:
- Webpack:基于打包(Bundle-based)
- 开发时需要打包整个应用
- 使用各种 loader 转换文件
- 生成一个或多个 bundle 文件
- Vite:基于 ESM(ES Module)
- 开发时利用浏览器原生 ESM 支持
- 按需编译,只处理当前页面需要的模块
- 生产环境使用 Rollup 打包
- Webpack:基于打包(Bundle-based)
- 开发服务器启动速度:
// Webpack 启动流程 1. 分析依赖图 2. 打包所有模块 3. 启动开发服务器 // Vite 启动流程 1. 启动开发服务器(几乎瞬间) 2. 按需编译请求的模块 - 热更新机制:
- Webpack HMR:需要重新打包相关模块
- Vite HMR:直接替换单个模块,速度更快
- 生产环境构建:
- Webpack:使用自身的打包能力
- Vite:使用 Rollup,生成更小的 bundle
7. Vue 3 Composition API 原理
问题: Vue 3 与 Vue 2 相比有哪些重要的改进?
详细答案:
- 响应式系统重写:
// Vue 2 - Object.defineProperty Object.defineProperty(obj, 'key', { get() { /* 依赖收集 */ }, set(newVal) { /* 触发更新 */ } }); // Vue 3 - Proxy new Proxy(target, { get(target, key) { /* 依赖收集 */ }, set(target, key, value) { /* 触发更新 */ } }); - Composition API 优势:
// 逻辑复用更简单 function useCounter() { const count = ref(0); const increment = () => count.value++; return { count, increment }; } // 在组件中使用 export default { setup() { const { count, increment } = useCounter(); return { count, increment }; } }; - 性能优化:
- Tree-shaking:未使用的 API 不会被打包
- 编译时优化:静态提升、内联组件 props
- Proxy 响应式:支持数组索引和对象属性的动态添加
- TypeScript 支持:
- 更好的类型推导
- 内置 TypeScript 支持
8. JavaScript 深拷贝实现
问题: 手写一个深拷贝函数。
详细答案:
function deepClone(obj, map = new WeakMap()) {
// 处理基本类型
if (obj === null || typeof obj !== 'object') {
return obj;
}
// 处理日期对象
if (obj instanceof Date) {
return new Date(obj.getTime());
}
// 处理正则对象
if (obj instanceof RegExp) {
return new RegExp(obj.source, obj.flags);
}
// 处理函数
if (typeof obj === 'function') {
return obj; // 函数通常不需要深拷贝
}
// 处理循环引用
if (map.has(obj)) {
return map.get(obj);
}
// 处理数组和对象
const cloned = Array.isArray(obj) ? [] : {};
map.set(obj, cloned);
// 处理 Symbol 属性
const symbolKeys = Object.getOwnPropertySymbols(obj);
symbolKeys.forEach(key => {
cloned[key] = deepClone(obj[key], map);
});
// 处理普通属性
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
cloned[key] = deepClone(obj[key], map);
}
}
return cloned;
}
// 测试用例
const original = {
name: 'test',
date: new Date(),
regex: /test/g,
nested: { value: 42 },
arr: [1, 2, { inner: 'value' }]
};
// 创建循环引用
original.self = original;
const cloned = deepClone(original);
console.log(cloned !== original); // true
console.log(cloned.self === cloned); // true
9. let、const、var 详细区别
问题: let、const 和 var 的区别是什么?什么是暂时性死区?
详细答案:
- 作用域差异:
// var - 函数作用域 function example1() { if (true) { var x = 1; } console.log(x); // 1,可以访问 } // let/const - 块级作用域 function example2() { if (true) { let y = 1; const z = 2; } console.log(y); // ReferenceError console.log(z); // ReferenceError } - 变量提升机制:
// var 提升并初始化为 undefined console.log(a); // undefined var a = 1; // let/const 提升但不初始化(暂时性死区) console.log(b); // ReferenceError let b = 2; console.log(c); // ReferenceError const c = 3; - 暂时性死区(TDZ):
function example() { // TDZ 开始 console.log(x); // ReferenceError let x = 1; // TDZ 结束 console.log(x); // 1 } - 重复声明:
// var 允许重复声明 var name = 'first'; var name = 'second'; // 正常 // let/const 不允许重复声明 let age = 18; let age = 20; // SyntaxError
10. CSS 盒模型详解
问题: 盒模型的理解,标准盒模型和 IE 盒模型的区别是什么?
详细答案:
- 标准盒模型(W3C):
.standard-box { width: 200px; /* 内容区宽度 */ padding: 20px; /* 内边距 */ border: 5px solid; /* 边框 */ margin: 10px; /* 外边距 */ } /* 实际占用宽度 = 200 + 20*2 + 5*2 + 10*2 = 270px */ /* 元素总宽度 = 200 + 20*2 + 5*2 = 250px */ - IE 盒模型(怪异模式):
.ie-box { box-sizing: border-box; width: 200px; /* 包含 content + padding + border */ padding: 20px; border: 5px solid; margin: 10px; } /* 内容区宽度 = 200 - 20*2 - 5*2 = 150px */ /* 实际占用宽度 = 200 + 10*2 = 220px */ - box-sizing 属性:
/* 标准盒模型 */ .content-box { box-sizing: content-box; /* 默认值 */ } /* IE 盒模型 */ .border-box { box-sizing: border-box; } - 实际应用:
/* 常用的全局设置 */ *, *::before, *::after { box-sizing: border-box; }
11. HTTP 状态码详解
问题: HTTP 常见的状态码有哪些?301 和 302 有什么区别?
详细答案:
- 1xx 信息响应:
- 100 Continue:客户端应继续请求
- 101 Switching Protocols:协议切换
- 2xx 成功响应:
- 200 OK:请求成功
- 201 Created:资源已创建
- 204 No Content:无内容返回
- 206 Partial Content:部分内容(断点续传)
- 3xx 重定向:
// 301 永久重定向 // 搜索引擎会更新索引,浏览器会缓存重定向 app.get('/old-page', (req, res) => { res.redirect(301, '/new-page'); }); // 302 临时重定向 // 搜索引擎不会更新索引,浏览器不会缓存 app.get('/temp-redirect', (req, res) => { res.redirect(302, '/temporary-page'); });- 304 Not Modified:资源未修改,使用缓存
- 4xx 客户端错误:
- 400 Bad Request:请求语法错误
- 401 Unauthorized:未授权
- 403 Forbidden:禁止访问
- 404 Not Found:资源不存在
- 405 Method Not Allowed:方法不允许
- 5xx 服务器错误:
- 500 Internal Server Error:服务器内部错误
- 502 Bad Gateway:网关错误
- 503 Service Unavailable:服务不可用
- 504 Gateway Timeout:网关超时
12. React Fiber 架构原理
问题: React Fiber 架构,它解决了什么问题?相比之前的 Stack Reconciler,主要有哪些变化?
详细答案:
- Stack Reconciler 的问题:
// 旧的递归调和过程 function reconcileChildren(element) { // 递归处理子元素,无法中断 element.children.forEach(child => { reconcileChildren(child); // 深度优先,一直递归到底 }); } - Fiber 架构的核心概念:
// Fiber 节点结构 const fiber = { type: 'div', // 组件类型 props: {}, // 属性 child: null, // 第一个子节点 sibling: null, // 兄弟节点 return: null, // 父节点 alternate: null, // 对应的 Fiber 节点(双缓存) effectTag: null, // 副作用标记 expirationTime: 0, // 过期时间 }; - 时间切片(Time Slicing):
function workLoop(deadline) { while (nextUnitOfWork && deadline.timeRemaining() > 1) { nextUnitOfWork = performUnitOfWork(nextUnitOfWork); } if (nextUnitOfWork) { // 还有工作未完成,继续调度 requestIdleCallback(workLoop); } } requestIdleCallback(workLoop); - 双缓存机制:
// current 树:当前显示的 UI // workInProgress 树:正在构建的新树 function commitRoot() { // 交换 current 和 workInProgress root.current = root.finishedWork; root.finishedWork = null; } - 优先级调度:
const priorities = { Immediate: 1, // 立即执行 UserBlocking: 2, // 用户交互 Normal: 3, // 正常优先级 Low: 4, // 低优先级 Idle: 5 // 空闲时执行 };
13. JavaScript 原型链详解
问题: 原型和原型链,proto 和 prototype 分别是什么?
详细答案:
- prototype 属性:
// 函数的 prototype 属性指向原型对象 function Person(name) { this.name = name; } Person.prototype.sayHello = function() { console.log(`Hello, I'm ${this.name}`); }; console.log(Person.prototype); // { sayHello: function, constructor: Person } - proto 属性:
// 对象的 __proto__ 属性指向构造函数的 prototype const person = new Person('Alice'); console.log(person.__proto__ === Person.prototype); // true console.log(person.__proto__.constructor === Person); // true - 原型链查找机制:
function Animal(name) { this.name = name; } Animal.prototype.eat = function() { console.log(`${this.name} is eating`); }; function Dog(name, breed) { Animal.call(this, name); this.breed = breed; } // 设置原型链 Dog.prototype = Object.create(Animal.prototype); Dog.prototype.constructor = Dog; Dog.prototype.bark = function() { console.log(`${this.name} is barking`); }; const dog = new Dog('Buddy', 'Golden Retriever'); // 原型链查找过程: // dog.bark() -> dog.__proto__.bark (Dog.prototype) // dog.eat() -> dog.__proto__.__proto__.eat (Animal.prototype) - 完整的原型链:
console.log(dog.__proto__ === Dog.prototype); // true console.log(dog.__proto__.__proto__ === Animal.prototype); // true console.log(dog.__proto__.__proto__.__proto__ === Object.prototype); // true console.log(dog.__proto__.__proto__.__proto__.__proto__ === null); // true
14. 浏览器渲染原理
问题: 描述一下浏览器渲染页面的完整过程?
详细答案:
- 渲染流程详解:
1. 解析 HTML → DOM 树 2. 解析 CSS → CSSOM 树 3. DOM + CSSOM → 渲染树(Render Tree) 4. 布局(Layout/Reflow)→ 计算元素位置和大小 5. 绘制(Paint)→ 填充像素 6. 合成(Composite)→ 图层合并 - 关键渲染路径优化:
<!-- 优化 CSS 加载 --> <link rel="preload" href="critical.css" as="style"> <link rel="stylesheet" href="critical.css"> <!-- 非关键 CSS 异步加载 --> <link rel="preload" href="non-critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'"> <!-- 优化 JavaScript 加载 --> <script src="app.js" defer></script> <script src="analytics.js" async></script> - 重排(Reflow)和重绘(Repaint):
// 触发重排的操作 element.style.width = '200px'; // 改变尺寸 element.style.display = 'none'; // 改变显示状态 element.offsetWidth; // 读取布局属性 // 只触发重绘的操作 element.style.color = 'red'; // 改变颜色 element.style.backgroundColor = 'blue'; // 改变背景色 // 优化:批量修改样式 element.style.cssText = 'width: 200px; height: 100px; color: red;'; // 或使用 CSS 类 element.className = 'optimized-style'; - 图层合成优化:
/* 创建新的合成层 */ .optimized { transform: translateZ(0); /* 或 will-change: transform */ /* GPU 加速,避免重排重绘 */ } /* 动画优化 */ @keyframes slide { from { transform: translateX(0); } to { transform: translateX(100px); } }
15. XSS 和 CSRF 防护详解
问题: 如何防止 XSS 和 CSRF 攻击?
详细答案:
-
XSS(跨站脚本攻击)防护:
// 1. 输入验证和过滤 function sanitizeInput(input) { return input .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, ''') .replace(/\//g, '/'); } // 2. 使用安全的 DOM 操作 // 危险:innerHTML element.innerHTML = userInput; // 可能执行脚本 // 安全:textContent element.textContent = userInput; // 只设置文本内容 // 3. CSP(内容安全策略) // HTTP 头或 meta 标签<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline';">// 4. HttpOnly Cookie res.cookie('sessionId', sessionId, { httpOnly: true, // 防止 JavaScript 访问 secure: true, // 只在 HTTPS 下传输 sameSite: 'strict' // 防止 CSRF }); -
CSRF(跨站请求伪造)防护:
// 1. CSRF Token // 服务端生成 token const csrfToken = crypto.randomBytes(32).toString('hex'); req.session.csrfToken = csrfToken; // 前端发送请求时携带 token fetch('/api/transfer', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrfToken }, body: JSON.stringify({ amount: 1000 }) }); // 服务端验证 token if (req.headers['x-csrf-token'] !== req.session.csrfToken) { return res.status(403).json({ error: 'Invalid CSRF token' }); } // 2. SameSite Cookie res.cookie('sessionId', sessionId, { sameSite: 'strict' // 严格模式,跨站请求不发送 cookie }); // 3. 验证 Referer const referer = req.headers.referer; if (!referer || !referer.startsWith('https://trusted-domain.com')) { return res.status(403).json({ error: 'Invalid referer' }); } // 4. 双重 Cookie 验证 const csrfCookie = req.cookies.csrfToken; const csrfHeader = req.headers['x-csrf-token']; if (csrfCookie !== csrfHeader) { return res.status(403).json({ error: 'CSRF token mismatch' }); }
16. WebSocket 实时通信实现
问题: 如何使用 WebSockets 来实现实时数据通信?
详细答案:
-
客户端实现:
class WebSocketClient { constructor(url) { this.url = url; this.ws = null; this.reconnectAttempts = 0; this.maxReconnectAttempts = 5; this.reconnectInterval = 1000; this.heartbeatInterval = 30000; this.heartbeatTimer = null; } connect() { try { this.ws = new WebSocket(this.url); this.setupEventListeners(); } catch (error) { console.error('WebSocket connection failed:', error); this.handleReconnect(); } } setupEventListeners() { this.ws.onopen = (event) => { console.log('WebSocket connected'); this.reconnectAttempts = 0; this.startHeartbeat(); this.onOpen?.(event); }; this.ws.onmessage = (event) => { try { const data = JSON.parse(event.data); if (data.type === 'pong') { // 心跳响应 return; } this.onMessage?.(data); } catch (error) { console.error('Failed to parse message:', error); } }; this.ws.onclose = (event) => { console.log('WebSocket disconnected:', event.code, event.reason); this.stopHeartbeat(); this.onClose?.(event); if (!event.wasClean) { this.handleReconnect(); } }; this.ws.onerror = (error) => { console.error('WebSocket error:', error); this.onError?.(error); }; } send(data) { if (this.ws && this.ws.readyState === WebSocket.OPEN) { this.ws.send(JSON.stringify(data)); } else { console.warn('WebSocket is not connected'); } } startHeartbeat() { this.heartbeatTimer = setInterval(() => { this.send({ type: 'ping', timestamp: Date.now() }); }, this.heartbeatInterval); } stopHeartbeat() { if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); this.heartbeatTimer = null; } } handleReconnect() { if (this.reconnectAttempts < this.maxReconnectAttempts) { this.reconnectAttempts++; console.log(`Attempting to reconnect (${this.reconnectAttempts}/${this.maxReconnectAttempts})`); setTimeout(() => { this.connect(); }, this.reconnectInterval * this.reconnectAttempts); } else { console.error('Max reconnection attempts reached'); } } close() { this.stopHeartbeat(); if (this.ws) { this.ws.close(1000, 'Client closing connection'); } } } // 使用示例 const client = new WebSocketClient('ws://localhost:8080'); client.onOpen = () => { console.log('Connected to server'); }; client.onMessage = (data) => { console.log('Received:', data); // 处理接收到的数据 }; client.connect(); -
服务端实现(Node.js):
const WebSocket = require('ws'); const http = require('http'); class WebSocketServer { constructor(port) { this.port = port; this.clients = new Map(); this.server = http.createServer(); this.wss = new WebSocket.Server({ server: this.server }); this.setupServer(); } setupServer() { this.wss.on('connection', (ws, req) => { const clientId = this.generateClientId(); const clientInfo = { id: clientId, ws: ws, ip: req.socket.remoteAddress, userAgent: req.headers['user-agent'], connectedAt: new Date() }; this.clients.set(clientId, clientInfo); console.log(`Client ${clientId} connected`); ws.on('message', (message) => { try { const data = JSON.parse(message); this.handleMessage(clientId, data); } catch (error) { console.error('Failed to parse message:', error); } }); ws.on('close', (code, reason) => { console.log(`Client ${clientId} disconnected:`, code, reason); this.clients.delete(clientId); }); ws.on('error', (error) => { console.error(`Client ${clientId} error:`, error); }); // 发送欢迎消息 this.sendToClient(clientId, { type: 'welcome', clientId: clientId, message: 'Connected to server' }); }); } handleMessage(clientId, data) { switch (data.type) { case 'ping': this.sendToClient(clientId, { type: 'pong', timestamp: Date.now() }); break; case 'broadcast': this.broadcast(data.message, clientId); break; case 'private': this.sendToClient(data.targetId, { type: 'private', from: clientId, message: data.message }); break; default: console.log(`Unknown message type: ${data.type}`); } } sendToClient(clientId, data) { const client = this.clients.get(clientId); if (client && client.ws.readyState === WebSocket.OPEN) { client.ws.send(JSON.stringify(data)); } } broadcast(message, excludeClientId = null) { this.clients.forEach((client, clientId) => { if (clientId !== excludeClientId && client.ws.readyState === WebSocket.OPEN) { client.ws.send(JSON.stringify({ type: 'broadcast', message: message, timestamp: Date.now() })); } }); } generateClientId() { return Math.random().toString(36).substr(2, 9); } start() { this.server.listen(this.port, () => { console.log(`WebSocket server listening on port ${this.port}`); }); } } // 启动服务器 const server = new WebSocketServer(8080); server.start();
17. TypeScript 高级特性
问题: TypeScript 的优势及其在项目中的应用。
详细答案:
-
类型系统优势:
// 1. 接口定义 interface User { id: number; name: string; email: string; roles: Role[]; } interface Role { id: number; name: string; permissions: Permission[]; } // 2. 泛型约束 function updateEntity<T extends { id: number }>(entity: T, updates: Partial<T>): T { return { ...entity, ...updates }; } // 3. 条件类型 type ApiResponse<T> = T extends string ? { message: T } : { data: T }; // 4. 映射类型 type ReadonlyUser = Readonly<User>; type PartialUser = Partial<User>; type UserKeys = keyof User; // 'id' | 'name' | 'email' | 'roles' // 5. 工具类型 type CreateUserRequest = Omit<User, 'id'>; type UpdateUserRequest = Pick<User, 'id'> & Partial<Omit<User, 'id'>>; -
高级类型应用:
// 1. 函数重载 function processData(data: string): string; function processData(data: number): number; function processData(data: boolean): boolean; function processData(data: string | number | boolean) { if (typeof data === 'string') { return data.toUpperCase(); } else if (typeof data === 'number') { return data * 2; } else { return !data; } } // 2. 装饰器 function Log(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function(...args: any[]) { console.log(`Calling ${propertyKey} with args:`, args); const result = originalMethod.apply(this, args); console.log(`${propertyKey} returned:`, result); return result; }; } class UserService { @Log createUser(userData: CreateUserRequest): Promise<User> { // 实现创建用户逻辑 return Promise.resolve({} as User); } } // 3. 模块声明 declare module '*.vue' { import { DefineComponent } from 'vue'; const component: DefineComponent<{}, {}, any>; export default component; } // 4. 命名空间 namespace API { export interface Request { url: string; method: 'GET' | 'POST' | 'PUT' | 'DELETE'; headers?: Record<string, string>; body?: any; } export interface Response<T = any> { status: number; data: T; message?: string; } } -
项目配置最佳实践:
// tsconfig.json { "compilerOptions": { "target": "ES2020", "module": "ESNext", "lib": ["ES2020", "DOM", "DOM.Iterable"], "moduleResolution": "node", "strict": true, "noImplicitAny": true, "noImplicitReturns": true, "noImplicitThis": true, "noUnusedLocals": true, "noUnusedParameters": true, "exactOptionalPropertyTypes": true, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "baseUrl": ".", "paths": { "@/*": ["src/*"], "@/components/*": ["src/components/*"], "@/utils/*": ["src/utils/*"] } }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] }