
1. TypeScript 面试题概述TypeScript 作为 JavaScript 的超集已经成为现代前端开发的标配技能。特别是在大型企业级项目中TypeScript 的类型系统能够显著提升代码质量和开发效率。根据近两年的前端招聘数据超过 80% 的中高级前端岗位都将 TypeScript 作为必备技能要求。这份面试题集萃整理了我作为面试官 5 年来最常考察的 TypeScript 核心知识点覆盖了从基础类型到高级类型的完整知识体系。无论你是准备面试的新手还是想巩固 TypeScript 基础的中级开发者这些题目都能帮助你系统性地检验自己的 TypeScript 掌握程度。2. 基础类型系统解析2.1 基本类型与类型声明TypeScript 的基础类型系统是理解整个类型体系的起点。除了 JavaScript 原有的 boolean、number、string 等基础类型外TypeScript 还扩展了以下特殊类型// 枚举类型 enum Direction { Up UP, Down DOWN } // 元组类型 let point: [number, number] [10, 20]; // void 类型函数 function logMessage(): void { console.log(This is a message); } // never 类型函数 function throwError(): never { throw new Error(Something went wrong); }在实际项目中我建议尽量避免使用 any 类型因为它会完全绕过类型检查。如果确实需要动态类型可以考虑使用 unknown 类型配合类型断言const userInput: unknown getUserInput(); // 先进行类型检查再使用 if (typeof userInput string) { console.log(userInput.toUpperCase()); }2.2 类型推断与类型断言TypeScript 的类型推断能力非常强大在大多数情况下我们不需要显式声明类型// 自动推断为 number 类型 let count 10; // 自动推断为 string[] 类型 const names [Alice, Bob];当我们需要覆盖 TypeScript 的类型推断时可以使用类型断言。但要注意类型断言只是告诉编译器相信我并不会进行实际的运行时检查const element document.getElementById(my-input) as HTMLInputElement; // 或者使用尖括号语法在 JSX 中不推荐 const value (HTMLInputElementelement).value;3. 高级类型特性3.1 接口与类型别名接口(interface)和类型别名(type)是 TypeScript 中定义复杂类型的两种主要方式。它们有很多相似之处但也有重要区别// 接口定义 interface User { id: number; name: string; } // 类型别名定义 type Point { x: number; y: number; }; // 接口可以扩展 interface Admin extends User { privileges: string[]; } // 类型别名可以使用联合类型 type ID number | string;在实际项目中我的经验法则是优先使用接口来定义对象结构只有在需要使用联合类型、元组或其他高级特性时才使用类型别名。3.2 泛型编程泛型是 TypeScript 中最强大的特性之一它允许我们创建可重用的组件// 泛型函数 function identityT(arg: T): T { return arg; } // 泛型接口 interface GenericArrayT { [index: number]: T; } // 泛型类 class GenericNumberT { zeroValue: T; add: (x: T, y: T) T; }在 React 组件开发中泛型特别有用interface PropsT { items: T[]; renderItem: (item: T) React.ReactNode; } function ListT({ items, renderItem }: PropsT) { return div{items.map(renderItem)}/div; }4. 实用工具类型TypeScript 提供了一系列内置的工具类型可以极大提高开发效率4.1 常用工具类型interface User { id: number; name: string; age?: number; email: string; } // 所有属性变为可选 type PartialUser PartialUser; // 挑选特定属性 type UserNameAndEmail PickUser, name | email; // 排除特定属性 type UserWithoutEmail OmitUser, email; // 所有属性变为只读 type ReadonlyUser ReadonlyUser;4.2 条件类型与映射类型TypeScript 的类型系统是图灵完备的这意味着我们可以编写非常复杂的类型逻辑// 条件类型 type NonNullableT T extends null | undefined ? never : T; // 映射类型 type OptionalKeysT { [K in keyof T]-?: undefined extends T[K] ? K : never; }[keyof T]; // 提取所有可选属性的键名 type UserOptionalKeys OptionalKeysUser; // age5. 类型声明与模块扩展5.1 声明全局类型在大型项目中我们经常需要扩展全局对象的类型定义// 扩展 Window 接口 declare global { interface Window { __APP_CONFIG__: { apiBaseUrl: string; env: development | production; }; } } // 使用全局扩展 const apiUrl window.__APP_CONFIG__.apiBaseUrl;5.2 第三方库类型定义当使用没有类型定义的第三方库时我们可以自己声明模块类型declare module legacy-library { export function doSomething(value: string): void; export const version: string; }对于流行的库更推荐使用 DefinitelyTyped 上的类型定义# 安装 React 的类型定义 npm install --save-dev types/react6. 实战经验与最佳实践6.1 避免 any 泛滥any 类型会完全破坏 TypeScript 的类型安全。以下是一些避免 any 的策略使用 unknown 代替 any 进行类型安全的动态类型处理为复杂数据结构定义精确的接口使用类型断言时添加明确的注释说明原因// 不好的做法 function parseData(data: any) { return JSON.parse(data); } // 改进做法 interface ApiResponse { status: success | error; data: unknown; } function parseData(data: string): ApiResponse { return JSON.parse(data) as ApiResponse; }6.2 类型守卫与类型缩小合理使用类型守卫可以让代码既安全又清晰function processValue(value: string | number) { if (typeof value string) { // 这里 value 被缩小为 string 类型 return value.toUpperCase(); } else { // 这里 value 被缩小为 number 类型 return value.toFixed(2); } }对于自定义类型可以使用用户定义的类型守卫interface Cat { meow(): void; } interface Dog { bark(): void; } function isCat(animal: Cat | Dog): animal is Cat { return meow in animal; } function handleAnimal(animal: Cat | Dog) { if (isCat(animal)) { animal.meow(); } else { animal.bark(); } }7. 常见面试问题深度解析7.1 类型兼容性TypeScript 使用结构化类型系统这与其他语言的名义类型系统不同interface Named { name: string; } class Person { constructor(public name: string) {} } let p: Named; p new Person(Alice); // OK因为结构兼容7.2 装饰器与元数据装饰器是 TypeScript 的高级特性广泛用于 Angular 等框架function log(target: any, key: string, descriptor: PropertyDescriptor) { const originalMethod descriptor.value; descriptor.value function(...args: any[]) { console.log(Calling ${key} with, args); const result originalMethod.apply(this, args); console.log(Result:, result); return result; }; return descriptor; } class Calculator { log add(a: number, b: number): number { return a b; } }8. 性能优化与高级技巧8.1 类型实例化深度限制当处理非常复杂的类型时可能会遇到类型实例化过深的错误。可以通过以下方式优化使用接口继承代替复杂的交叉类型将大型类型拆分为多个小型类型在适当的地方使用类型断言8.2 项目配置优化合理的 tsconfig.json 配置可以显著提高开发体验{ compilerOptions: { strict: true, noImplicitAny: true, strictNullChecks: true, moduleResolution: node, esModuleInterop: true, skipLibCheck: true, forceConsistentCasingInFileNames: true } }9. 最新特性与未来趋势TypeScript 5.0 引入了多项重要改进装饰器标准化的实验性支持性能优化和编译速度提升更强大的类型推导能力对 ECMAScript 新特性的更好支持在项目中逐步采用新特性时建议先在小型模块中试验确保团队所有成员都理解新特性建立相应的代码审查规范10. 面试实战建议在 TypeScript 相关的技术面试中我通常会考察以下几个方面对类型系统基本原理的理解实际项目中类型设计的经验解决复杂类型问题的能力对 TypeScript 生态的了解准备面试时建议深入理解至少一个流行框架如 React 或 Vue的 TypeScript 集成练习手写常见工具类型如 Partial、Required 等准备 2-3 个实际项目中遇到的 TypeScript 挑战案例最后提醒一点TypeScript 的知识体系非常庞大面试中更重要的是展示你的学习能力和解决问题的思路而不是死记硬背所有细节。