前端面试之吊打面试官 TypeScript 篇

153 阅读4分钟

 本文为作者在前端面试过程中所遇到的 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 的原始数据类型有哪些?

  1. number

所有数字均为浮点数,支持二进制、八进制和十六进制表示。

let decimal: number = 6;
let binary: number = 0b1010; // ES6 二进制

  1. string

支持单引号或双引号定义字符串。

let name: string = "Alice";

  1. boolean

布尔值类型。

let isDone: boolean = false;

  1. void

表示无返回值的函数。

function logMessage(): void {
  console.log("This has no return value.");
}

  1. nullundefined

独立的原始类型,默认是所有类型的子类型。

let u: undefined = undefined;
let n: null = null;


34. TypeScript 目前的稳定版本是什么?

截至最近更新,TypeScript 4.2.3 是官方稳定版本。


35. TypeScript 和 JavaScript 的区别是什么?

特性TypeScriptJavaScript
类型系统静态类型(编译时检查)动态类型(运行时检查)
面向对象完整支持类、接口、继承基于原型链
错误检测编译阶段暴露错误需运行时调试
工具支持强大的 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. nevervoid 的区别

  • 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 的核心概念与使用技巧。