以下是一些常见的 TypeScript 面试题:
一、 基础与核心概念
-
为什么要使用 TypeScript?它相比 JavaScript 有哪些优势?
- 考察点:静态类型检查(提前发现错误)、代码可读性与可维护性、更好的开发工具支持(智能感知、重构)、面向对象特性增强、更好的团队协作。
-
TypeScript 与 JavaScript 的关系是什么?
- 考察点:TypeScript 是 JavaScript 的超集(Superset)。任何有效的 JavaScript 代码也是有效的 TypeScript 代码。TypeScript 最终会被编译成 JavaScript 运行。
-
什么是静态类型(Static Typing)和动态类型(Dynamic Typing)?TypeScript 属于哪种?
- 考察点:类型检查的时机(编译时 vs 运行时)。TypeScript 提供的是静态类型检查。
-
什么是类型注解(Type Annotation)?什么是类型推断(Type Inference)?
- 考察点:显式指定类型 (: string) vs 编译器自动推断类型。何时需要显式注解?
-
TypeScript 中有哪些基本(原始)数据类型?
- 考察点:string, number, boolean, null, undefined, symbol, bigint。
-
any, unknown, void, never 类型分别是什么意思?它们有什么区别?
-
考察点:
- any:任意类型,关闭类型检查(应避免使用)。
- unknown:类型未知,是 any 的类型安全版本,使用前需要进行类型检查或断言。
- void:通常用于表示函数没有返回值。
- never:表示永远不会有返回值的类型(如抛出异常、无限循环)。
- any vs unknown 的区别是关键。
-
二、 类型定义与接口
-
如何在 TypeScript 中定义数组类型?
- 考察点:Type[] 和 Array 两种语法。联合类型数组 (string | number)[]。
-
什么是元组(Tuple)类型?它和数组有什么区别?
- 考察点:固定长度、固定位置类型的数组。与普通数组在长度和类型灵活性上的差异。
-
interface (接口) 和 type (类型别名) 有什么区别?应该如何选择?
-
考察点:
- 共同点:都可以定义对象形状。
- interface 特点:声明合并、可继承 (extends)、可被类实现 (implements)。主要用于定义对象/类结构契约。
- type 特点:更灵活,可以为任何类型创建别名(联合、交叉、元组、原始类型等),不能声明合并,通常用于定义联合/交叉类型或使用高级类型。
- 选择:定义公共 API 或期望被扩展用 interface,定义联合/交叉类型或简单类型别名用 type,应用内部对象两者皆可,看团队规范。
-
-
如何在接口或类型别名中定义可选属性和只读属性?
- 考察点:? 用于可选属性,readonly 关键字用于只读属性。
-
如何在 TypeScript 中定义函数类型?
- 考察点:使用类型别名 (type MyFunc = (a: number) => string;)、使用接口调用签名 (interface MyFunc { (a: number): string; })、内联注解。
三、 泛型 (Generics)
-
什么是泛型?为什么要使用泛型?
- 考察点:编写可重用、灵活且类型安全的代码。解决 any 类型丢失信息和为每种类型写重复代码的问题。类型参数化。
-
如何定义和使用泛型函数、泛型接口、泛型类?
- 考察点:使用尖括号 声明类型参数,在参数、返回值、成员中使用类型参数。显式指定类型 vs 类型推断。
-
什么是泛型约束?如何使用 extends 关键字添加约束?
- 考察点:限制泛型类型参数必须满足某种结构或继承关系,提高泛型函数/类的内部类型安全性。例如 。
-
keyof 操作符的作用是什么?它通常和泛型约束一起用在什么场景?
- 考察点:获取一个类型的所有公共属性名的联合类型。常用于约束一个类型参数必须是另一个类型参数的属性名,如 getProperty<T, K extends keyof T>(obj: T, key: K)。
四、 类与枚举
-
TypeScript 类(Class)相比 ES6 类有哪些增强?
- 考察点:访问修饰符 (public, private, protected)、只读属性 (readonly)、抽象类 (abstract)、接口实现 (implements)、参数属性(在构造函数参数前加修饰符直接定义成员)。
-
访问修饰符 public, private, protected 的区别?
- 考察点:public(默认,哪里都能访问)、private(只能在类内部访问)、protected(类内部和子类内部可以访问)。
-
什么是枚举(Enum)类型?它的应用场景?
- 考察点:为一组相关的常量提供更友好的名称。数字枚举 vs 字符串枚举。反向映射(数字枚举)。应用(状态码、类型区分等)。
五、 高级类型与类型操作
-
联合类型(Union Types, |)和交叉类型(Intersection Types, &)是什么?
- 考察点:联合类型表示“或”(满足其中一个类型即可),交叉类型表示“与”(必须同时满足所有类型特征,常用于合并对象类型)。
-
类型断言(Type Assertion)是什么?有哪些语法?它和类型转换有什么区别?
- 考察点:告诉编译器“我知道这个值的类型是什么,你不用检查了”。语法 (value as Type 或 value)。它只影响编译时检查,不改变运行时的值和行为(不是类型转换)。滥用会破坏类型安全。
-
typeof 和 instanceof 在 TypeScript 中作为类型守卫(Type Guard)的作用?
- 考察点:在 if 语句等条件块中,typeof 可以缩小原始类型的范围,instanceof 可以缩小对象实例类型的范围,从而在块内安全地访问特定类型的属性或方法。
-
什么是条件类型(Conditional Types)?(T extends U ? X : Y)
- 考察点:根据一个类型是否满足某个条件来决定最终的类型。常用于创建复杂的类型工具。
-
什么是映射类型(Mapped Types)?它们有什么用?
- 考察点:基于一个现有类型创建新类型,可以转换原类型的属性(如 readonly, ?)或值类型。内置的 Partial, Readonly, Pick<T, K>, Record<K, T> 等都是映射类型。
六、 编译与配置
-
tsconfig.json 文件是做什么的?有哪些重要的配置项?
- 考察点:TypeScript 编译器的配置文件。重要配置项:target(编译目标 JS 版本)、module(模块系统)、outDir(输出目录)、rootDir(源文件根目录)、strict(启用所有严格检查)、esModuleInterop(模块互操作)、lib(包含的库定义)、include/exclude(编译范围)。
-
声明文件(.d.ts)是做什么用的?
- 考察点:为 JavaScript 库或模块提供类型信息,使得在 TypeScript 中可以安全地使用它们,并获得类型检查和智能提示。Ambient Declarations(环境声明)。
七、 实践与场景
-
如何在 TypeScript 项目中使用 JavaScript 库?
- 考察点:检查是否有官方或社区提供的 @types/ 声明文件,安装它。如果没有,可能需要自己编写声明文件或使用 declare module '...'。
-
如何在 React/Vue 等框架中使用 TypeScript?有哪些需要注意的地方?
- 考察点:组件属性(Props)的类型定义、状态(State)的类型定义、事件处理函数的类型、Hooks 或 Composition API 的类型推断。
-
描述一下你使用 TypeScript 过程中遇到过的挑战以及如何解决的?
- 考察点:实际经验、解决问题的能力。可能是类型定义复杂、与 JS 库集成困难、类型推断不符合预期等。