TypeScript的高频面试题

118 阅读6分钟

一、基础概念有关的

1. TypeScript是什么?与JavaScript的主要区别?

-   **答案**:TypeScript是JavaScript的超集,添加了静态类型、接口、泛型等特性,需编译为JS运行。区别在于:

    -   TS支持编译时类型检查,JS仅在运行时发现类型错误
    -   TS支持面向对象特性(类、接口、继承),JS需通过原型链实现
    -   TS提供更好的开发工具支持(如自动补全、重构)

TypeScript 的主要优势

  1. 静态类型检查:编译时发现错误,降低 Bug 率。
  2. 更好的代码可读性:类型标注让代码更清晰。
  3. 支持 ES6+ 语法:TS 兼容 JS,同时支持最新特性。
  4. 强大的类型系统:支持接口、枚举、泛型等。
  5. IDE 支持更强:更好的自动补全类型提示跳转

TS vs JS 主要区别

TypeScriptJavaScript
类型检查静态类型检查运行时检查
编译需要编译成 JS直接运行
ES6+ 支持默认支持需 Babel 转换
接口 / 泛型支持不支持
IDE 体验强类型提示、自动补全依赖 JSdoc

2. 类型声明(Type Annotation)与类型推断(Type Inference)的区别

-   **答案**    -   **类型声明**:显式指定变量类型,如 `let x: number = 10;`
    -   **类型推断**:TS根据赋值自动推断类型,如 `let y = 20;`(推断为`number`

二、类型系统

3. anyunknown类型的区别

-   **答案**:

    -   `any`:绕过类型检查,失去TS优势,适用于兼容旧代码
    -   `unknown`:需通过类型断言或类型守卫缩小类型范围,更安全

    ```
    let a: any = "hello";
    a.toFixed(); // 不报错(运行时可能出错)
    let b: unknown = "world";
    (b as string).toUpperCase(); // 需类型断言
    ```

4. 接口(Interface)与类型别名(Type Alias)的区别

-   **答案**    -   **接口**:描述对象结构,支持声明合并(多次定义自动扩展)
    -   **类型别名**:可为任意类型命名(联合、交叉、元组等),不支持合并

    ```
    interface Person { name: string; }
    type ID = string | number;
    ```

5. 联合类型(Union Types)与交叉类型(Intersection Types)

-   **答案**    -   **联合类型**`string | number`,变量可为多种类型之一
    -   **交叉类型**`A & B`,变量需同时满足两种类型的结构

三、高级特性

6. 泛型(Generics)的作用及示例

-   **答案**:泛型用于创建可复用的组件,保持类型安全。

    ```
    function identity<T>(arg: T): T { return arg; }
    let output = identity<string>("hello"); // 显式指定类型
    let inferred = identity(42); // 自动推断为number
    ```

    -   应用场景:函数、类、接口中处理多种数据类型

7. 枚举(Enum)与常量枚举(Const Enum)的区别

-   **答案**    -   **普通枚举**:编译后生成对象,允许计算值
    -   **常量枚举**:编译时删除,仅允许常量成员,提升性能

    ```
    enum Color { Red, Green } // 普通枚举
    const enum Direction { Up, Down } // 常量枚举
    ```

8. 类型守卫(Type Guards)的作用及实现方式

-   **答案**:缩小条件块中的变量类型范围,常用方式:

    -   `typeof`、`instanceof`
    -   自定义类型谓词函数(`is`语法)

    ```
    function isString(val: unknown): val is string {
      return typeof val === "string";
    }
    ```

四、工程化与配置

9. 如何处理可空类型(Nullable Types)?

-   **答案**:使用联合类型`T | null | undefined`,结合可选链操作符(`?.`)和非空断言(`!`)

    ```
    let name: string | null = null;
    console.log(name?.toUpperCase()); // 安全访问
    ```

10. tsconfig.json中的关键配置项

-   **答案**    -   `strict`:启用所有严格类型检查(如`strictNullChecks`    -   `target`:指定编译目标(如`ES6`    -   `module`:模块系统(如`CommonJS``ESNext`

5、装饰器与模块化

11. 装饰器(Decorators)的应用场景

-   **答案**:用于扩展类、方法、属性等,常见于框架(如Angular)中:

    -   **类装饰器**:修改类构造函数
    -   **方法装饰器**:拦截方法调用

    ```
    @sealed
    class Greeter { /* ... */ }
    ```

12. 模块(Module)与命名空间(Namespace)的区别

-   **答案**    -   **模块**:基于文件(`import/export`),适用于现代工程
    -   **命名空间**:逻辑分组代码,避免全局污染,逐渐被模块替代

13. ** TypeScript 的基本数据类型有哪些?**

TS 的基本类型

let num: number = 10;       // 数字类型
let str: string = "hello";  // 字符串类型
let isDone: boolean = true; // 布尔类型
let arr: number[] = [1, 2, 3]; // 数组
let arr2: Array<string> = ["a", "b", "c"]; // 泛型数组
let tuple: [string, number] = ["hello", 42]; // 元组
enum Color { Red, Green, Blue } // 枚举
let anyVar: any = "任意类型"; // any 类型
let voidVar: void = undefined; // void 类型
let neverVar: never; // never 类型

📌 14. TypeScript 接口(interface)的作用?

interface 用于定义对象的结构

interface Person {
  name: string;
  age: number;
  sayHello(): void;
}

const user: Person = {
  name: "张三",
  age: 25,
  sayHello() {
    console.log("你好");
  },
};
  • 接口可以继承
interface Employee extends Person {
  job: string;
}

const worker: Employee = {
  name: "李四",
  age: 30,
  job: "前端开发",
  sayHello() {
    console.log("你好");
  },
};

📌 15. TypeScript 的类型断言(Type Assertion)是什么?

类型断言用于告诉 TypeScript 我们更清楚变量的类型

let someValue: any = "Hello TypeScript";

// 方式 1: 使用 `as`
let strLength: number = (someValue as string).length;

// 方式 2: 使用 `<类型>`
let strLength2: number = (<string>someValue).length;

💡 注意类型断言不会转换数据,只是告诉 TS 这个值是什么类型!


📌 16. TypeScript 泛型(Generics)是什么?

泛型Generics)用于定义可复用的类型

function identity<T>(arg: T): T {
  return arg;
}

console.log(identity<string>("Hello")); // "Hello"
console.log(identity<number>(42)); // 42

泛型接口

interface Box<T> {
  value: T;
}

let stringBox: Box<string> = { value: "Hello" };
let numberBox: Box<number> = { value: 123 };

泛型约束

function logLength<T extends { length: number }>(arg: T): void {
  console.log(arg.length);
}

logLength("hello"); // ✅ 字符串有 length
logLength([1, 2, 3]); // ✅ 数组有 length
// logLength(42); ❌ 报错:number 没有 length

📌 17. typeinterface 的区别?

区别interfacetype
作用定义对象结构定义类型别名
扩展性可以继承(extends不能继承
联合类型❌ 不支持✅ 支持
声明合并✅ 会自动合并❌ 不会合并

示例

interface Person {
  name: string;
}
type PersonAlias = { name: string };

// 扩展(interface 可以扩展)
interface Employee extends Person {
  job: string;
}

// 联合类型(type 可以联合)
type ID = string | number;

💡 interface 更适合对象结构,type 更适合联合类型。


📌 18. TypeScript 的 readonlyconst 有什么区别?

readonly 只作用于 对象的属性

interface Person {
  readonly id: number;
  name: string;
}

const user: Person = { id: 1, name: "张三" };
// user.id = 2; // ❌ 报错:id 只读

const 只作用于 变量

const age: number = 18;
// age = 20; // ❌ 报错:常量不能修改

💡 简单理解

  • readonly 保护 对象属性
  • const 保护 变量

📌 19. TypeScript unknown vs any 的区别?

区别unknownany
类型安全✅ 安全❌ 不安全
赋值限制✅ 需要类型检查❌ 任意赋值
适用场景更安全的 any 替代品逃避类型检查

示例

let value: unknown = "Hello";
let text: string;

// text = value; // ❌ 报错:不能直接赋值
if (typeof value === "string") {
  text = value; // ✅ 类型检查后可以赋值
}

💡 unknown 是比 any 更安全的选择,推荐优先使用 unknown


📌 20. TypeScript 中 PickOmitPartialRequired 的作用?

Pick<T, K>:选取部分属性

interface User {
  id: number;
  name: string;
  age: number;
}
type UserInfo = Pick<User, "id" | "name">; // 只选取 id 和 name

Omit<T, K>:去掉某些属性

type UserWithoutAge = Omit<User, "age">; // 移除 age

Partial<T>:所有属性变为可选

type PartialUser = Partial<User>; // { id?: number; name?: string; age?: number; }

Required<T>:所有属性变为必填

type RequiredUser = Required<PartialUser>;