本文为作者在前端面试过程中所遇到的 TypeScript 相关面试题汇总,并附上详细解答,覆盖类型系统、类型操作、泛型、高级类型、实用技巧等多个维度。希望能帮助你在面试中游刃有余,吊打面试官!
1. TypeScript 与 JavaScript 的区别?
答: TS 是 JS 的超集,加入了静态类型检查、接口、枚举、泛型、装饰器等特性,最终编译成 JS 运行在浏览器或 Node 环境中。
2. TypeScript 是强类型还是弱类型语言?
答: TS 是强类型语言,支持静态类型系统,类型错误会在编译阶段被发现。
3. interface 和 type 有什么区别?
答:
interface支持继承和合并声明,更适合描述对象结构。type更灵活,可用于联合类型、交叉类型、映射类型等,不能重复声明。
4. 什么时候用 interface,什么时候用 type?
答: 通常推荐优先使用 interface,只有当需要类型操作或联合类型等场景时才使用 type。
5. 什么是类型断言?
答: 类型断言用于手动指定一个值的类型:value as Type 或 <Type>value。
6. 如何实现一个类型为数字或字符串的参数?
function fn(val: number | string) {}
7. 什么是字面量类型?
答: 字面量类型限制变量只能是某个特定的值,如:
let direction: 'left' | 'right';
8. keyof 的作用?
答: 提取某个类型的键组成联合类型。
type A = keyof { name: string; age: number }; // 'name' | 'age'
9. typeof 的使用场景?
答: 获取变量的类型。
const user = { name: 'Tom', age: 18 };
type User = typeof user;
10. 条件类型的写法?
type IsString<T> = T extends string ? true : false;
11. infer 是做什么的?
答: 在条件类型中推断类型:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
12. 泛型的基本使用?
function identity<T>(arg: T): T {
return arg;
}
13. 泛型约束?
function logLength<T extends { length: number }>(arg: T): number {
return arg.length;
}
14. 什么是 Partial?
答: 将 T 的所有属性变为可选。
15. 什么是 Required?
答: 将 T 的所有属性变为必填。
16. 什么是 Readonly?
答: 将 T 的所有属性变为只读。
17. 什么是 Pick<T, K>?
答: 从 T 中选择一组属性构造新的类型。
18. 什么是 Omit<T, K>?
答: 从 T 中排除一组属性构造新的类型。
19. Record<K, T> 是什么?
答: 创建一个对象类型,键为 K,值为 T。
type Roles = Record<'admin' | 'user', string>;
20. unknown 与 any 的区别?
答: unknown 更安全,不能直接对其操作,需类型判断;any 则跳过类型检查。
21. never 类型的场景?
答: 表示永远不会有返回值的类型,比如抛出异常或无限循环的函数。
22. 如何定义元组?
let tuple: [string, number];
23. 枚举 enum 使用?
enum Direction {
Up = 1,
Down,
Left,
Right
}
24. 模板字面量类型是什么?
type Event = `on${Capitalize<'click' | 'hover'>}`;
25. 实现一个深度只读类型 DeepReadonly?
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K]
};
26. 如何实现数组转联合类型?
const arr = ['a', 'b', 'c'] as const;
type Union = typeof arr[number];
27. 实现一个 Exclude 类型?
type MyExclude<T, U> = T extends U ? never : T;
28. 如何提取函数的参数类型?
type Params<T> = T extends (...args: infer P) => any ? P : never;
29. typeof 与 keyof 联合使用?
const person = { name: 'Tom', age: 18 };
type PersonKeys = keyof typeof person;
30. 使用泛型实现一个 curry 函数类型定义?
type Curry<P extends any[], R> =
P extends [infer A, ...infer B]
? (arg: A) => Curry<B, R>
: R;
31. TypeScript 的主要特点是什么?
跨平台
TypeScript 编译器支持所有主流操作系统(Windows、macOS、Linux),开发者可以在任意平台上编写和编译代码。
ES6 特性支持
TypeScript 原生支持 ECMAScript 2015 (ES6) 的大部分特性,如箭头函数、解构赋值、模块化等。
面向对象
提供完整的面向对象编程能力,支持类(Class)、接口(Interface)、模块(Module)等特性。
静态类型检查
在编译时进行类型检查,帮助开发者提前发现类型错误,减少运行时异常。
let age: number = 25;
age = "30"; // 编译时报错:不能将字符串赋值给 number 类型
可选的静态类型
允许开发者逐步为 JavaScript 代码添加类型注解,而非强制要求所有代码静态化。
DOM 操作支持
可直接操作浏览器 DOM,适合前端开发场景。
32. 使用 TypeScript 有什么好处?
- 代码可读性:显式类型注解使代码结构更清晰。
- 编译时错误检查:减少运行时错误。
- 跨平台兼容性:通过编译可生成兼容各环境的 JavaScript 代码。
- 强大的工具支持:IDE 智能提示、重构功能完善。
- 社区与生态:被 Slack、Asana 等大型项目采用,社区资源丰富。
33. TypeScript 的原始数据类型有哪些?
number
所有数字均为浮点数,支持二进制、八进制和十六进制表示。
let decimal: number = 6;
let binary: number = 0b1010; // ES6 二进制
string
支持单引号或双引号定义字符串。
let name: string = "Alice";
boolean
布尔值类型。
let isDone: boolean = false;
void
表示无返回值的函数。
function logMessage(): void {
console.log("This has no return value.");
}
null和undefined
独立的原始类型,默认是所有类型的子类型。
let u: undefined = undefined;
let n: null = null;
34. TypeScript 目前的稳定版本是什么?
截至最近更新,TypeScript 4.2.3 是官方稳定版本。
35. TypeScript 和 JavaScript 的区别是什么?
| 特性 | TypeScript | JavaScript |
| 类型系统 | 静态类型(编译时检查) | 动态类型(运行时检查) |
| 面向对象 | 完整支持类、接口、继承 | 基于原型链 |
| 错误检测 | 编译阶段暴露错误 | 需运行时调试 |
| 工具支持 | 强大的 IDE 智能提示 | 有限支持 |
| 学习曲线 | 需掌握类型系统和额外语法 | 入门简单 |
36. 为什么要用 TypeScript?
- 代码健壮性:类型系统减少潜在错误。
- 大型项目维护:清晰的类型注解便于团队协作。
- 渐进式迁移:可逐步为现有 JavaScript 项目添加类型。
- 未来兼容性:支持最新的 ECMAScript 标准。
37. TypeScript 和 JavaScript 哪个更好?
- TypeScript 适合大型项目、团队协作或需要严格类型控制的场景。
- JavaScript 更适合小型项目或快速原型开发。
- 两者关系:TypeScript 是 JavaScript 的超集,最终编译为 JavaScript 运行。
38. 什么是泛型?
泛型允许在定义函数、接口或类时不预先指定具体类型,使用时再动态指定。
示例:创建一个通用数组生成函数
function createArray<T>(length: number, value: T): T[] {
return Array(length).fill(value);
}
// 使用
const strArray = createArray<string>(3, "x"); // string[]
const numArray = createArray(3, 100); // number[](自动类型推断)
39. TS 中的类
TypeScript 类支持面向对象特性,如继承、封装、多态:
class Animal {
constructor(public name: string) {}
move(distance: number = 0) {
console.log(`${this.name} moved ${distance}m`);
}
}
class Dog extends Animal {
bark() {
console.log("Woof!");
}
}
const dog = new Dog("Buddy");
dog.bark(); // "Woof!"
dog.move(10); // "Buddy moved 10m"
40. 构造函数与方法重写
- 构造函数:通过
constructor初始化对象。 - 方法重写:子类覆盖父类方法实现自定义行为。
class Bird extends Animal {
override move(distance = 5) { // 重写父类方法
super.move(distance); // 调用父类实现
console.log("Flying...");
}
}
41. 接口类型
可索引类型接口
约束数组或对象的结构:
// 数组约束
interface StringArray {
[index: number]: string;
}
let arr: StringArray = ["A", "B"];
// 对象约束
interface StringMap {
[key: string]: string;
}
let obj: StringMap = { name: "Alice" };
函数类型接口
定义函数签名:
interface SearchFunc {
(source: string, keyword: string): boolean;
}
const search: SearchFunc = (src, kw) => src.includes(kw);
类类型接口
约束类的行为:
interface ClockInterface {
currentTime: Date;
setTime(d: Date): void;
}
class Clock implements ClockInterface {
currentTime: Date = new Date();
setTime(d: Date) {
this.currentTime = d;
}
}
42. never 和 void 的区别
void:表示函数无返回值,但可正常结束。
function noReturn(): void {
console.log("This returns nothing.");
}
never:表示函数无法正常结束(抛出异常或无限循环)。
function error(message: string): never {
throw new Error(message);
}
43. TypeScript 的学前基础
- JavaScript 基础:变量、函数、作用域等。
- ES6+ 特性:箭头函数、解构、Promise 等。
- 面向对象概念:类、继承、多态。
44. 编译 TypeScript
手动编译
tsc app.ts # 生成 app.js
监听模式(自动编译)
tsc --watch app.ts
45. 类型别名 vs 接口
类型别名( type ) | 接口( interface ) |
| 可定义任意类型(联合、交叉) | 仅定义对象类型 |
| 不可重复声明 | 可合并声明(多次定义自动扩展) |
| 不支持继承 | 支持 extends 继承 |
| 适合非对象类型 | 适合对象和类的约束 |
示例:
type ID = string | number;
interface User {
id: ID;
name: string;
}
通过这些问题与解答,可以系统性地掌握 TypeScript 的核心概念与使用技巧。