TypeScript 高频面试题与核心知识总结

本文系统梳理 TypeScript 面试高频问题,涵盖类型系统、泛型、类型工具、进阶实战等核心要点,适合面试复习与查漏补缺。


类型系统

  1. declarevar 有什么不同?
  • var 用于声明并定义变量,会在编译后的 JS 代码中生成实际变量声明。

  • declare 只用于类型声明,不会生成实际代码,常用于声明全局变量或第三方库类型。

  • 示例:

    typescript 复制代码
    var foo = 123; // 编译后有 var foo = 123;
    declare var bar: number; // 仅类型声明,编译后无实际代码
  1. TypeScript 和 JavaScript 有哪些主要区别?
  • TypeScript 是 JavaScript 的超集,增加了静态类型、接口、枚举、泛型等特性。
  • 需要编译为 JavaScript 执行,支持最新 ECMAScript 特性。
  • 类型检查可提前发现错误,提升代码可维护性和可读性。
  • 支持类型推断、类型保护、类型工具等。
  1. interface 和 type 有什么区别?各自适用场景是什么?
  • interface 适合描述对象结构、可多次声明自动合并、支持继承和实现。

  • type 可用于基本类型、联合/交叉类型、映射类型,不能重复声明。

  • 推荐优先用 interface,复杂类型组合用 type

  • 示例:

    typescript 复制代码
    interface A { x: number }
    interface A { y: string } // 合并为 { x: number; y: string }
    type B = { x: number }
    // type B = { y: string } // 报错,不能重复声明
  1. 如何定义只读属性?readonly 和 const 有什么区别?
  • readonly 修饰对象属性,只能在声明或构造函数中赋值。

  • const 修饰变量,绑定引用不可变,但对象属性可变。

  • 示例:

    typescript 复制代码
    interface Point { readonly x: number; readonly y: number }
    const p: Point = { x: 1, y: 2 }
    // p.x = 3 // 报错
  1. TypeScript 支持哪些访问修饰符?分别有什么作用?
  • public(默认):任何地方可访问。

  • private:仅类内部可访问。

  • protected:类及其子类可访问。

  • 示例:

    typescript 复制代码
    class Animal {
      public name: string
      protected age: number
      private secret: string
      constructor() {
        this.name = 'cat'
        this.age = 2
        this.secret = 'hidden'
      }
    }
    class Cat extends Animal {
      getAge() { return this.age } // ok
      // getSecret() { return this.secret } // 报错
    }
  1. 什么是类型断言?与类型转换有何不同?
  • 类型断言是告诉编译器"我知道这个值的类型",不会影响运行时,只影响类型检查。

  • 类型转换会在运行时改变变量的实际类型或值。

  • 类型断言语法:<Type>valuevalue as Type

  • 示例:

    typescript 复制代码
    const someValue: any = "hello"
    const strLen: number = (someValue as string).length
  1. 什么是联合类型(Union Types)和交叉类型(Intersection Types)?举例说明。
  • 联合类型:变量可以是多种类型之一,使用 | 连接。

    typescript 复制代码
    function format(input: string | number) {
      if (typeof input === 'string') return input.trim()
      return input.toFixed(2)
    }
  • 交叉类型:将多个类型合并为一个类型,使用 & 连接。

    typescript 复制代码
    type A = { a: number }
    type B = { b: string }
    type AB = A & B // { a: number; b: string }
    const ab: AB = { a: 1, b: 'hi' }
  1. TypeScript 中的枚举(enum)是如何工作的?有哪些使用场景?
  • 枚举用于定义一组有名字的常量,支持数字和字符串枚举。

  • 使用场景:状态码、选项类型等。

    typescript 复制代码
    enum Direction { Up = 1, Down, Left, Right }
    enum Status { Success = 'success', Fail = 'fail' }
    function move(dir: Direction) {}
  1. 如何定义和使用元组(Tuple)类型?
  • 元组用于表示已知数量和类型的数组。

    typescript 复制代码
    let tuple: [string, number, boolean]
    tuple = ['hello', 10, true]
    // 支持可选元素和剩余元素
    type Flexible = [string, ...number[]]
  1. 什么是类型别名?如何使用?
  • 类型别名用 type 关键字为类型起一个新名字,适合复杂类型或联合类型。

    typescript 复制代码
    type Name = string
    type Point = { x: number; y: number }
    type RequestStatus = 'pending' | 'success' | 'fail'

泛型与类型工具

  1. 泛型的作用是什么?请举例说明。
  • 泛型提升代码复用性和类型安全,常用于函数、接口、类。

    typescript 复制代码
    function identity<T>(arg: T): T { return arg }
    let a = identity<number>(123)
    let b = identity('abc') // 自动推断
  1. 请解释一下 TypeScript 中的泛型约束。
  • 使用 extends 限定泛型类型范围。

    typescript 复制代码
    interface Lengthwise { length: number }
    function logLength<T extends Lengthwise>(arg: T): void {
      console.log(arg.length)
    }
    logLength([1,2,3])
    logLength('hello')
    // logLength(123) // 报错
  1. 如何定义泛型接口和泛型类?举例说明。
  • 泛型接口:

    typescript 复制代码
    interface ApiResult<T> {
      code: number
      data: T
      msg?: string
    }
    const userResult: ApiResult<{name: string}> = { code: 0, data: { name: 'Tom' } }
  • 泛型类:

    typescript 复制代码
    class Stack<T> {
      private arr: T[] = []
      push(item: T) { this.arr.push(item) }
      pop(): T | undefined { return this.arr.pop() }
    }
    const s = new Stack<number>()
    s.push(1)
  1. 如何在 TypeScript 中实现函数重载?
  • 通过多个签名声明和一个实现体实现。

    typescript 复制代码
    function join(a: string, b: string): string
    function join(a: number, b: number): number
    function join(a: any, b: any): any {
      return a + b
    }
    const r1 = join('a', 'b') // string
    const r2 = join(1, 2) // number
  1. Partial、Pick、Omit 等工具类型的作用和用法是什么?
  • Partial<T>:所有属性可选。

  • Pick<T, K>:挑选部分属性。

  • Omit<T, K>:排除部分属性。

  • Readonly<T>:所有属性只读。

  • Record<K, T>:构造具有指定属性的类型。

    typescript 复制代码
    interface User { id: number; name: string; age: number }
    type UserPartial = Partial<User>
    type UserName = Pick<User, 'name'>
    type UserWithoutAge = Omit<User, 'age'>
    type UserMap = Record<'a'|'b', User>
  1. TypeScript 如何与第三方 JavaScript 库集成?如何声明类型?
  • 安装 @types/xxx 类型声明包,或手写 .d.ts 文件。

  • 使用 declare moduledeclare vardeclare function 等声明外部类型。

    typescript 复制代码
    // global.d.ts
    declare module 'my-lib'
    declare var $: (selector: string) => any

条件类型与类型工具

  1. 请解释一下 TypeScript 中的条件类型。
  • 条件类型允许根据类型关系选择不同类型,语法:T extends U ? X : Y

    typescript 复制代码
    type IsString<T> = T extends string ? true : false
    type A = IsString<'abc'> // true
    type B = IsString<123>   // false
  1. 什么是类型守卫(Type Guard)?有哪些常见的实现方式?
  • 类型守卫用于在运行时判断变量类型,缩小类型范围。

  • 常见方式:typeofinstanceof、自定义类型保护函数(返回 arg is Type)。

    typescript 复制代码
    function isDate(x: unknown): x is Date {
      return x instanceof Date
    }
    function handle(val: string | Date) {
      if (isDate(val)) {
        val.getFullYear()
      } else {
        val.trim()
      }
    }
  1. 什么是 never 类型?它有哪些应用场景?
  • never 表示永远不会有值的类型,常用于抛出异常或无限循环的函数返回类型。

    typescript 复制代码
    function fail(msg: string): never {
      throw new Error(msg)
    }
    function endless(): never {
      while(true){}
    }
  1. TypeScript 中的可选链(Optional Chaining)和空值合并运算符(Nullish Coalescing)如何使用?
  • 可选链:obj?.prop,安全访问嵌套属性。

  • 空值合并:value ?? defaultValue,仅当 value 为 null 或 undefined 时返回默认值。

    typescript 复制代码
    const user = { info: { name: 'Tom' } }
    const name = user.info?.name
    const age = user.info?.age ?? 18
  1. TypeScript 的命名空间(namespace)和模块(module)有什么区别?
  • 命名空间用于组织全局代码,适合小型项目。
  • 模块基于文件,使用 import/export,适合大型项目和代码分割。
  1. 如何配置 tsconfig.json?常用的配置项有哪些?
  • target:编译目标 JS 版本。

  • module:模块系统。

  • strict:严格类型检查。

  • include/exclude:编译包含/排除文件。

  • outDir:输出目录。

  • 示例:

    json 复制代码
    {
      "compilerOptions": {
        "target": "ES6",
        "module": "commonjs",
        "strict": true,
        "outDir": "./dist"
      },
      "include": ["src/**/*"],
      "exclude": ["node_modules"]
    }

进阶与实战

  1. TypeScript 如何实现类型推断?有哪些常见场景?
  • 根据变量初始值、函数返回值、参数默认值等自动推断类型。

    typescript 复制代码
    let num = 123 // 推断为 number
    function add(a = 1, b = 2) { return a + b } // 返回 number
    const arr = [1, 2, 3] // number[]
  1. TypeScript 如何实现类型兼容性?什么是鸭子类型?
  • TypeScript 采用结构类型系统(鸭子类型),只要结构兼容即可赋值。

    typescript 复制代码
    interface A { x: number }
    interface B { x: number; y: string }
    let a: A = { x: 1 }
    let b: B = { x: 1, y: 'hi' }
    a = b // 兼容
  1. 如何自定义类型守卫?举例说明。
  • 返回 arg is Type 的函数即可自定义类型守卫。

    typescript 复制代码
    function isNumber(val: unknown): val is number {
      return typeof val === 'number'
    }
    function process(val: string | number) {
      if (isNumber(val)) {
        return val.toFixed(2)
      }
      return val.trim()
    }
  1. TypeScript 中如何实现 Mixin(混入)?
  • 通过高阶函数返回类实现混入。

    typescript 复制代码
    type Constructor<T = {}> = new (...args: any[]) => T
    function Timestamped<TBase extends Constructor>(Base: TBase) {
      return class extends Base {
        timestamp = Date.now()
      }
    }
    class Person { name = 'Tom' }
    const TimestampedPerson = Timestamped(Person)
    const p = new TimestampedPerson()
  1. TypeScript 如何处理 this 的类型?
  • 可通过箭头函数自动绑定 this,或在方法前显式声明 this 类型。

    typescript 复制代码
    class MyClass {
      name = 'TS'
      log(this: MyClass) {
        console.log(this.name)
      }
    }
  1. 如何声明全局变量和全局类型?
  • .d.ts 文件中用 declare 声明全局变量、类型、模块。

    typescript 复制代码
    // global.d.ts
    declare var GLOBAL_CONST: string
    declare function globalFn(a: number): void
    declare module 'my-lib'
  1. TypeScript 如何实现装饰器(Decorator)?有哪些应用场景?
  • 装饰器用于类、属性、方法、参数的元编程,常见于日志、权限、依赖注入等场景。

    typescript 复制代码
    function log(target: any, key: string, descriptor: PropertyDescriptor) {
      const original = descriptor.value
      descriptor.value = function(...args: any[]) {
        console.log(`调用${key}参数:`, args)
        return original.apply(this, args)
      }
    }
    class Demo {
      @log
      foo(a: number) { return a * 2 }
    }
  1. TypeScript 如何实现类型映射(Mapped Types)?
  • 通过 in 关键字遍历属性名生成新类型。

    typescript 复制代码
    type Readonly<T> = { readonly [P in keyof T]: T[P] }
    type Nullable<T> = { [P in keyof T]: T[P] | null }
  1. TypeScript 如何处理异步类型(如 Promise)?
  • 为 Promise 指定泛型参数,描述 resolve 的类型。

    typescript 复制代码
    function fetchData(): Promise<{name: string}> {
      return Promise.resolve({ name: 'TS' })
    }
  1. TypeScript 如何与 React、Vue 等框架结合使用?
  • React:使用 @types/react,通过泛型和类型声明约束 props、state、ref 等。

    typescript 复制代码
    interface Props { name: string }
    const Hello: React.FC<Props> = ({ name }) => <div>{name}</div>
  • Vue:使用 defineComponentPropType<T>ref<T>() 等类型辅助函数。

  1. TypeScript 如何实现类型过滤(如 Exclude、Extract)?
  • Exclude<T, U>:从 T 中排除可以赋值给 U 的类型。

  • Extract<T, U>:从 T 中提取可以赋值给 U 的类型。

    typescript 复制代码
    type T1 = Exclude<'a' | 'b' | 'c', 'a'> // 'b' | 'c'
    type T2 = Extract<'a' | 'b' | 'c', 'a' | 'd'> // 'a'
  1. TypeScript 如何实现递归类型?
  • 递归类型用于描述嵌套结构,如树形结构。

    typescript 复制代码
    type Tree<T> = {
      value: T
      children?: Tree<T>[]
    }
  1. TypeScript 如何声明只读数组和元组?
  • 使用 readonly 修饰符。

    typescript 复制代码
    const arr: readonly number[] = [1, 2, 3]
    const tuple: readonly [number, string] = [1, 'a']
  1. TypeScript 如何实现类型合并和扩展?
  • 通过交叉类型(&)或接口继承(extends)实现类型合并和扩展。

    typescript 复制代码
    interface A { a: number }
    interface B { b: string }
    type AB = A & B
    interface C extends A, B { c: boolean }
  1. TypeScript 如何处理类型循环引用?
  • 可以通过类型别名、接口递归引用自身实现循环引用。

    typescript 复制代码
    interface Node {
      value: number
      next?: Node
    }

高频进阶题与类型体操

  1. 如何实现深部分可选类型?

    typescript 复制代码
    type DeepPartial<T> = {
      [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]
    }
  2. 如何实现类型安全的事件系统?

    typescript 复制代码
    type EventMap = {
      click: { x: number; y: number }
      keydown: { key: string }
    }
    class Emitter<T extends Record<string, any>> {
      on<K extends keyof T>(event: K, handler: (payload: T[K]) => void) {}
    }
  3. 如何声明联合字面量类型?

    typescript 复制代码
    type Direction = 'up' | 'down' | 'left' | 'right'
    function move(dir: Direction) {}
  4. 如何实现类型安全的 API 响应结构?

    typescript 复制代码
    interface ApiResponse<T> {
      code: number
      data: T
      error?: string
    }
  5. 如何利用 infer 实现类型提取?

    typescript 复制代码
    type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any
    type ParamType<T> = T extends (arg: infer P) => any ? P : never
  6. 如何实现类型安全的表单数据校验?

    • 利用泛型、映射类型、条件类型组合。
    typescript 复制代码
    type Validator<T> = { [K in keyof T]: (value: T[K]) => boolean }
    function validate<T>(data: T, validators: Validator<T>): boolean {
      return Object.keys(validators).every(
        key => validators[key as keyof T](data[key as keyof T])
      )
    }

面试建议:掌握 TypeScript 的类型系统、泛型、类型工具、类型推断与守卫、常用配置与第三方库集成,能灵活举例和解释原理,能手写常见类型工具和类型体操题,是面试高分的关键。

相关推荐
张志鹏PHP全栈4 小时前
TypeScript 第一天,认识TypeScript
typescript
羊八井9 小时前
类型、分类定义时使用 type 还是 kind ?
rust·typescript·代码规范
MR_发9 小时前
万字实现带@和表情包的输入框
vue.js·typescript
OEC小胖胖20 小时前
告别 undefined is not a function:TypeScript 前端开发优势与实践指南
前端·javascript·typescript·web
三水气象台21 小时前
用户中心Vue3网页开发(1.0版)
javascript·css·vue.js·typescript·前端框架·html·anti-design-vue
難釋懷1 天前
TypeScript-webpack
javascript·webpack·typescript
摸鱼仙人~2 天前
如何创建基于 TypeScript 的 React 项目
javascript·react.js·typescript
一生躺平的仔3 天前
TypeScript入门(九)装饰器:TypeScript的"元编程超能力"
typescript
MiyueFE3 天前
让我害怕的 TypeScript 类型 — — 直到我学会了这 3 条规则
前端·typescript