Typescript 面试题目整理

2/26/2026 typescriptinterview

# 🎯 Typescript 面试题目整理

# 1. 什么是泛型?

泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

核心优势:

  • 代码复用:同一套逻辑可用于多种类型
  • 类型安全:编译时进行类型检查
  • 灵活性:保持类型约束的同时提供灵活性

常见应用场景:

// 1. 泛型函数
function identity<T>(arg: T): T {
  return arg;
}

const num = identity<number>(123);     // 显式指定
const str = identity("hello");         // 类型推断

// 2. 泛型接口
interface Box<T> {
  value: T;
}

const box: Box<string> = { value: "test" };

// 3. 泛型类
class GenericNumber<T> {
  zeroValue: T;
  add: (x: T, y: T) => T;
}

// 4. 泛型约束
interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length);
  return arg;
}

// 5. 常用工具泛型
// Partial<T> - 所有属性变为可选
// Required<T> - 所有属性变为必需
// Readonly<T> - 所有属性变为只读
// Pick<T, K> - 选取部分属性
// Omit<T, K> - 排除部分属性

# 2. type 和 interface 的区别

特性 interface type
定义方式 interface Person { } type Person = { }
扩展方式 extends 关键字 交叉类型 &
合并行为 支持声明合并 不支持
适用范围 只能定义对象结构 可定义任何类型(联合、元组、基本类型等)

关键区别详解:

// 1. 声明合并(interface 独有)
interface User {
  name: string;
}

interface User {
  age: number;
}
// 合并为:{ name: string; age: number; }

// type 会报重复定义错误
type Animal = { species: string };
// type Animal = { legs: number };  // ❌ Error

// 2. 扩展语法不同
interface Animal {
  name: string;
}

interface Dog extends Animal {
  breed: string;
}

// 使用 type 实现类似效果
type Person = { name: string };
type Employee = Person & { role: string };  // 交叉类型

// 3. type 能定义更丰富的类型
type StringOrNumber = string | number;      // 联合类型
type Pair = [string, number];               // 元组类型
type Direction = 'up' | 'down' | 'left';    // 字面量类型
type GetName = () => string;                // 函数类型

// interface 只能定义对象形状
// interface GetName = () => string;  // ❌ Error

使用建议:

  • 定义对象结构、需要声明合并 → 用 interface
  • 定义联合类型、元组、函数类型等复杂类型 → 用 type
  • 很多场景下两者可以互换,保持代码库一致性更重要

# 3. any、unknown、never 的区别

这三个类型代表了 TypeScript 中类型安全的三个极端:

# any - 类型系统中的"后门"

let anything: any = 42;
anything = "hello";        // ✅ 可以赋任何值
anything.foo.bar;          // ✅ 任意属性访问
anything();                // ✅ 任意调用
anything[0][1];            // ✅ 任意索引访问
  • 特点:完全放弃类型检查,可以赋值给任何类型
  • 用途:逐步迁移 JS 项目、处理动态数据
  • 风险:破坏类型安全,应尽量避免使用

# unknown - 类型安全的 any

let value: unknown = 42;

value = "hello";           // ✅ 可以赋任何值

// value.foo.bar;          // ❌ Error: 必须先收窄类型
// value();                // ❌ Error: 必须先收窄类型

// 使用前必须进行类型检查
if (typeof value === "string") {
  console.log(value.toUpperCase());  // ✅ TypeScript 知道这里是 string
}

// 类型断言/收窄
const str = value as string;         // ⚠️ 需要自己保证正确
  • 特点:可以接受任何值,但使用前必须确定类型
  • 用途:处理不确定类型的数据、API 返回值
  • 优势:强制开发者做类型检查,比 any 更安全

# never - 不可能存在的类型

// 1. 永不返回的函数
function throwError(message: string): never {
  throw new Error(message);
}

function infiniteLoop(): never {
  while (true) {}
}

// 2. 类型收窄的终点
function getArea(shape: Shape) {
  switch (shape.type) {
    case 'circle': return Math.PI * shape.radius ** 2;
    case 'square': return shape.side ** 2;
    default:
      const _exhaustiveCheck: never = shape;  // ✅ 确保处理所有情况
      return _exhaustiveCheck;
  }
}

// 3. 空数组类型推断
const emptyArray = [];              // 类型为 never[]
emptyArray.push(1);                  // ✅ 推断为 number[]
  • 特点:表示永远不存在的值类型
  • 用途:抛异常函数、死循环、穷尽类型检查
  • 特性:never 是所有类型的子类型,可以赋值给任何类型

# 三者关系图

类型范围:
┌─────────────────────────────────────┐
│           any (最宽泛)               │
│  ┌───────────────────────────────┐  │
│  │    unknown (安全的最宽泛)       │  │
│  │   ┌─────────────────────────┐  │  │
│  │   │   具体类型 (string, etc) │  │  │
│  │   │   ┌───────────────────┐  │  │  │
│  │   │   │   never (最窄)     │  │  │  │
│  │   │   └───────────────────┘  │  │  │
│  │   └─────────────────────────┘  │  │
│  └───────────────────────────────┘  │
└─────────────────────────────────────┘

赋值关系:
any      ← never ✅  (never 可赋值给任何类型)
unknown  ← never ✅
string   ← never ✅

any ← unknown ❌  (unknown 不能赋值给 any 以外的类型)
any ← string  ❌

最佳实践:

// ❌ 避免 any
function processData(data: any) { }

// ✅ 优先 unknown
function processData(data: unknown) {
  if (isValidData(data)) {
    // 使用 data
  }
}

// ✅ never 用于穷尽检查
type Shape = Circle | Square;
function assertNever(x: never): never {
  throw new Error("Unexpected object: " + x);
}