【前端高频面试题】 - TypeScript 篇,零基础入门到精通,收藏这篇就够了

【前端高频面试题】 - TypeScript 篇

1. 请解释 TypeScript 是什么?它与 JavaScript 的核心区别是什么?

面试回答需突出 TS 的核心价值(类型安全)和与 JS 的关键差异,结构清晰:

  • TypeScript 定义:TS 是 JavaScript 的超集(Superset),在 JS 语法基础上增加了静态类型系统,最终会编译为纯 JS 运行(支持所有 JS 环境),核心目标是提升代码可维护性、减少运行时错误。
  • 与 JavaScript 的核心区别(分点对比):
    1. 类型系统:TS 有静态类型(编译阶段检查类型,变量声明时需指定/推断类型);JS 是动态类型(运行时才确定类型,易出现类型错误)。
    2. 编译阶段:TS 需通过编译器(如 tsc)编译为 JS 才能运行(编译时会做类型校验);JS 可直接在浏览器/Node 环境运行。
    3. 特性补充:TS 新增接口(Interface)、泛型(Generic)、枚举(Enum)、类型守卫等特性;JS 无这些原生类型相关特性。
    4. 开发体验:TS 支持 IDE 智能提示、自动补全、类型错误提前预警;JS 开发时需手动判断类型,错误难提前发现。

2. TypeScript 支持哪些基本数据类型?请分别说明。

需覆盖原始类型、特殊类型,明确各类型的用途,实习中常用类型优先:

  • 原始类型(与 JS 一致,需显式标注):
    1. string:字符串类型,如 let name: string = "张三"
    2. number:数字类型(含整数、浮点数),如 let age: number = 22
    3. boolean:布尔类型(true/false),如 let isStudent: boolean = true
    4. null:空值类型,需开启 strictNullChecks 才会单独识别,如 let empty: null = null
    5. undefined:未定义类型,同上,如 let unassigned: undefined = undefined
    6. symbol:唯一标识类型(ES6 特性),如 let id: symbol = Symbol("uniqueId")
    7. bigint:大整数类型(处理超出 number 范围的数值),如 let bigNum: bigint = 100n
  • 特殊类型(TS 新增,实习高频):
    1. any:任意类型(关闭类型检查,不推荐滥用),如 let random: any = "hello"(后续可赋值为数字)。
    2. unknown:未知类型(比 any 安全,需类型断言后使用),如 let value: unknown = 123(需 value as number 后才能调用数字方法)。
    3. void:无返回值类型(常用于函数返回值),如 function log(): void { console.log("log") }
    4. never:永不存在的类型(如抛出错误的函数、无限循环函数的返回值),如 function throwErr(): never { throw new Error("err") }

3. 接口(Interface)和类型别名(Type Alias)的区别是什么?分别在什么场景下使用?

这是实习面试必问(易混淆),需分“相同点”“不同点”“使用场景”:

  • 相同点
    1. 均可定义对象/函数类型,如 interface User { name: string }type User = { name: string }
    2. 均可支持泛型,如 interface Box<T> { value: T }type Box<T> = { value: T }
  • 核心区别
    1. 扩展方式
      • Interface:通过 extends 扩展,如 interface Student extends User { age: number }
      • Type Alias:通过交叉类型(&)扩展,如 type Student = User & { age: number }
    2. 合并能力
      • Interface:支持“声明合并”(同名接口会自动合并属性),如 interface User { name: string }interface User { age: number } 合并为 { name: string; age: number }
      • Type Alias:不支持声明合并(同名会报错)。
    3. 适用范围
      • Interface:仅能定义对象/函数类型,不能定义基础类型(如 interface Num = number 报错)。
      • Type Alias:可定义任意类型(基础类型、联合类型、交叉类型等),如 type StrOrNum = string | number
  • 使用场景
    1. 优先用 Interface:定义组件 Props、API 返回数据结构等需“可扩展/合并”的对象类型(符合团队协作中类型迭代的需求)。
    2. 优先用 Type Alias:定义联合类型、交叉类型、基础类型别名(如 type ID = string | number),或需要复用复杂类型时。

4. 什么是泛型(Generic)?为什么需要泛型?请举一个实习中常用的例子。

泛型是 TS 核心特性(实习中复用组件/工具函数必用),需讲清“定义”“作用”“实例”:

  • 泛型定义:泛型是“类型参数化”的语法,允许在定义函数、接口、类时不指定具体类型,而是在使用时动态传入类型(类似函数的参数传递),语法用 <T>(T 为类型占位符,可自定义名称)。
  • 为什么需要泛型(解决两个核心问题):
    1. 类型安全:避免使用 any 导致的类型丢失(如用 any 定义数组,无法约束数组元素类型)。
    2. 代码复用:一套逻辑支持多种类型(如一个“获取数组第一个元素”的函数,可同时支持 string 数组、number 数组)。

实习常用例子(以“通用数组工具函数”为例):```
// 1. 定义泛型函数:获取数组第一个元素
function getFirstElement(arr: T[]): T | undefined {
return arr[0];
}// 2. 使用时传入具体类型(或 TS 自动推断)
const strArr: string[] = [“a”, “b”];
const firstStr = getFirstElement(strArr); // TS 推断 T 为 string,返回值类型为 string | undefinedconst numArr: number[] = [1, 2];
const firstNum = getFirstElement(numArr); // 显式指定 T 为 number

5. 什么是类型断言(Type Assertion)?有哪几种方式?使用时需要注意什么?

类型断言是“手动指定类型”的语法(实习中操作 DOM、处理未知类型时常用),需讲清“定义”“方式”“注意事项”:

  • 类型断言定义:当 TS 无法自动推断变量类型时,开发者明确告知 TS“该变量的实际类型”,强制 TS 按指定类型处理(仅编译阶段生效,不影响运行时)。
  • 两种常用方式
  • 使用注意事项
    1. 不能断言“完全无关的类型”(如 let num: number = 123 as string 会报错),仅能断言“兼容的类型”(如 unknown 断言为 stringHTMLElement 断言为 HTMLInputElement)。
    2. 避免滥用:优先让 TS 自动推断类型,仅在类型不确定时使用(滥用会抵消 TS 的类型安全优势)。

尖括号语法(不支持 JSX 场景,易与 JSX 标签冲突):```
const input = document.getElementById(“username”);

as 语法(推荐,支持所有场景,如 JSX):```
// 例子:获取 DOM 元素(TS 无法确定元素类型,需断言为 HTMLInputElement)
const input = document.getElementById(“username”) as HTMLInputElement;
input.value = “test”; // 断言后可安全调用 input 元素的 value 属性

6. any、unknown、never、void 这四种特殊类型的区别是什么?分别在什么场景下使用?

这四种类型易混淆,需对比说明“含义”“使用场景”,突出实习中的高频用法:

类型核心含义关键特性实习常用场景
any任意类型(关闭类型检查)可赋值给任意类型,任意类型可赋值给它;可调用任意方法(无类型校验)临时兼容旧 JS 代码(不推荐主动使用)
unknown未知类型(安全的 any)仅能赋值给 any/unknown;需断言后才能调用方法接收未知来源的值(如 API 返回数据、用户输入)
void无返回值仅函数返回值可用;仅 undefined 可赋值给它(开启 strictNullChecks 时)定义无返回值的函数(如 console.log 类函数)
never永不存在的类型不能赋值给任何类型,任何类型也不能赋值给它;无任何属性/方法定义抛出错误的函数、无限循环函数的返回值

例子对比:```
// any:无类型检查,易出错
let anyVal: any = “hello”;
anyVal(); // 编译不报错,运行时会报错(字符串不能调用)// unknown:需断言后使用,更安全
let unknownVal: unknown = “hello”;
(unknownVal as string).length; // 断言为 string 后可调用 length// void:无返回值函数
function logMsg(): void {
console.log(“msg”); // 无 return 或 return undefined
}// never:永无返回的函数
function infiniteLoop(): never {
while (true) {} // 无限循环,永远不会返回
}

7. 如何在 TypeScript 中定义“可选属性”和“只读属性”?请举例说明。

这是定义对象类型的基础(实习中定义组件 Props、API 结构常用),需讲清“语法”“特性”“例子”:

  • 1. 可选属性
    • 语法:在属性名后加 ?,表示该属性“可存在、可不存在”。
    • 特性:访问可选属性时,TS 会自动判断是否为 undefined(避免运行时错误)。
  • 2. 只读属性
    • 语法:在属性名前加 readonly,表示该属性“初始化后不能修改”。
    • 特性:仅限制“重新赋值”,若属性是对象,对象内部属性仍可修改(浅只读)。

实习例子(定义不可修改的 ID):```
interface User {
readonly id: string; // 只读属性
name: string;
}const user: User = { id: “123”, name: “张三” };
user.name = “李四”; // 正确(非只读属性可修改)
user.id = “456”; // 错误(只读属性不能重新赋值)

实习例子(定义用户信息,age 为可选):```
interface User {
name: string; // 必选属性
age?: number; // 可选属性(可省略)
}const user1: User = { name: “张三” }; // 正确(age 省略)
const user2: User = { name: “李四”, age: 22 }; // 正确(age 存在)

8. 什么是联合类型(Union Type)和交叉类型(Intersection Type)?请分别举例说明使用场景。

两种类型组合方式(实习中处理“多类型参数”“合并类型”常用),需对比“定义”“语法”“例子”:

  • 1. 联合类型(Union Type)
    • 定义:表示变量的类型是“多个类型中的任意一个”,用 | 分隔类型,核心是“或”的关系。
    • 语法:TypeA | TypeB | TypeC
    • 实习场景:处理“参数可能有多种类型”的情况(如函数参数支持 string 或 number)。
  • 2. 交叉类型(Intersection Type)
    • 定义:表示变量的类型是“多个类型的合并”,包含所有类型的属性/方法,用 & 分隔类型,核心是“且”的关系。
    • 语法:TypeA & TypeB & TypeC
    • 实习场景:处理“合并多个类型”的情况(如合并基础用户信息和权限信息)。

例子(合并 User 和 Permission 类型):```
interface User {
name: string;
age: number;
}interface Permission {
role: string;
hasEdit: boolean;
}type UserWithPermission = User & Permission; // 交叉类型:包含 User 和 Permission 的所有属性const admin: UserWithPermission = {
name: “张三”,
age: 22,
role: “admin”,
hasEdit: true,
}; // 正确(需包含所有属性)

例子(定义支持字符串/数字的 ID):```
type ID = string | number; // 联合类型:ID 是 string 或 number// 函数参数支持 ID 类型
function getUserById(id: ID): void {
if (typeof id === “string”) {
console.log(“字符串 ID:”, id);
} else {
console.log(“数字 ID:”, id);
}
}getUserById(“123”); // 正确
getUserById(456); // 正确

9. 什么是类型守卫(Type Guard)?常用的类型守卫有哪些?请举例说明。

类型守卫是“判断联合类型具体类型”的工具(实习中处理联合类型逻辑必用),需讲清“定义”“常用方式”“例子”:

  • 类型守卫定义:在运行时检查变量的类型,让 TS 在代码块内部自动推断出变量的具体类型(缩小类型范围,避免类型错误)。
  • 常用类型守卫方式(按实习高频度排序):

自定义类型守卫(通过函数返回 param is Type 语法自定义):

interface User { id: string; name: string; } // 自定义守卫:判断是否为 User 类型 function isUser(data: unknown): data is User { return ( typeof data === "object" && data !== null && "id" in data && "name" in data && typeof (data as User).id === "string" ); } const apiData: unknown = { id: "123", name: "张三" }; if (isUser(apiData)) { console.log(apiData.name); // TS 推断 apiData 为 User } 

in 守卫(判断对象是否包含某个属性):

interface Dog { bark: () => void; } interface Cat { meow: () => void; } function makeSound(animal: Dog | Cat): void { if ("bark" in animal) { animal.bark(); // TS 推断 animal 为 Dog } else { animal.meow(); // TS 推断 animal 为 Cat } } 

instanceof 守卫(判断引用类型:数组、类实例等):

type ArrOrObj = number[] | { value: number }; function getValue(data: ArrOrObj): number { if (data instanceof Array) { return data[0]; // TS 推断 data 为 number[] } else { return data.value; // TS 推断 data 为 { value: number } } } 

typeof 守卫(判断基础类型:string/number/boolean/symbol):

type StrOrNum = string | number; function getLength(value: StrOrNum): number { if (typeof value === "string") { return value.length; // TS 推断 value 为 string(可调用 length) } else { return value.toString().length; // TS 推断 value 为 number } } 

10. 如何将 TypeScript 集成到 Vue 项目中?(实习高频,以 Vue3 + Vite 为例)

Vue 是前端实习高频框架,需讲清“集成步骤”“核心配置”“实习常用场景(如组件 Props 类型)”:

  • 2. 核心配置文件(了解关键配置,面试可提及):
    • tsconfig.json:TS 编译配置,核心字段:
      • compilerOptions.strict: true:开启严格模式(强制类型校验,推荐开启)。
      • compilerOptions.lib: ["ESNext", "DOM"]:指定依赖的库(支持 ES 新特性和 DOM API)。
      • compilerOptions.types: ["vite/client"]:引入 Vite 客户端类型(支持 import.meta.env 等)。
    • vite.config.ts:Vite 配置文件(用 TS 编写,需导出 defineConfig 对象)。

3. 实习常用场景:组件中使用 TS(以 <script setup lang="ts"> 为例,Vue3 推荐语法):

<template> <div>{{ username }} ({{ age }})</div> <button @click="updateAge">增加年龄</button> </template> <script setup lang="ts"> // 1. 定义 Props 类型(用 defineProps + 泛型) const props = defineProps<{ username: string; // 必选 Props age?: number; // 可选 Props }>(); // 2. 定义响应式变量(TS 自动推断类型) import { ref } from "vue"; const count = ref(0); // TS 推断 count 为 Ref<number> // 3. 定义函数(指定参数/返回值类型) function updateAge(): void { if (props.age) { // 若 age 存在,+1(TS 自动推断 props.age 为 number) console.log(props.age + 1); } } </script> 

1. 初始化 Vue + TS 项目(Vite 方式,最常用):

# 1. 执行创建命令,选择 Vue + TypeScript npm create vite@latest my-vue-ts-project -- --template vue-ts # 2. 安装依赖并启动 cd my-vue-ts-project npm install npm run dev 

11. 什么是枚举(Enum)?它有什么作用?请举例说明数字枚举和字符串枚举的区别。

枚举是“命名常量集合”(实习中处理“固定状态”常用,如订单状态、按钮类型),需讲清“定义”“分类”“例子”:

  • 枚举定义:TS 中用于定义“一组有名字的常量”,使代码更具可读性(替代魔法值,如用 OrderStatus.PENDING 替代 1),语法用 enum 关键字。
  • 核心作用
    1. 提高代码可读性(常量有语义化名称)。
    2. 约束取值范围(只能从枚举中选择值,避免非法值)。
  • 两种常用枚举类型
  • 实习使用建议:优先用字符串枚举(语义更清晰,无反向映射冗余),仅在需要数字标识时用数字枚举。

字符串枚举(值为字符串,需显式指定每个值,无自动递增):

// 例子:定义按钮类型(每个值需显式指定字符串) enum ButtonType { PRIMARY = "primary", SECONDARY = "secondary", DANGER = "danger", } // 使用:仅支持通过名称取 value(无反向映射) function renderButton(type: ButtonType): void { console.log(`渲染 ${type} 类型按钮`); } renderButton(ButtonType.PRIMARY); // 正确(只能传枚举中的值) renderButton("normal"); // 错误(非法值,TS 报错) 

数字枚举(默认,值为数字,支持自动递增):

// 例子:定义订单状态(未指定值时,从 0 开始递增) enum OrderStatus { PENDING, // 0(默认) PAID, // 1(自动递增) SHIPPED, // 2 DELIVERED, // 3 } // 使用:可通过名称取 value,也可通过 value 取名称 const status: OrderStatus = OrderStatus.PAID; console.log(status); // 1 console.log(OrderStatus[1]); // "PAID"(数字枚举支持反向映射) 

12. 什么是声明文件(.d.ts)?它的作用是什么?请举例说明使用场景。

声明文件是“描述 JS 模块类型”的文件(实习中引入第三方 JS 库时常用),需讲清“定义”“作用”“例子”:

  • 声明文件定义:以 .d.ts 为后缀的文件,用于告诉 TS“某个 JS 模块/变量的类型”(仅包含类型声明,无具体代码逻辑),让 TS 能识别 JS 代码的类型。
  • 核心作用:解决“TS 无法识别 JS 模块类型”的问题,常见场景:
    1. 引入无 TS 类型的第三方 JS 库(如一些老的 jQuery 插件)。
    2. 自定义 JS 模块,需为其提供类型声明(如实习中封装的 JS 工具函数)。

实习常用场景例子
场景 1:为第三方 JS 库写声明文件(如引入 lodash 无类型时):

// 1. 安装官方声明文件(优先,大多数库有 @types 包) npm install @types/lodash --save-dev // 2. 若无官方声明文件,手动创建 lodash.d.ts declare module "lodash" { export function debounce(func: (...args: any[]) => void, wait: number): (...args: any[]) => void; // 声明需要用到的方法类型 } // 3. 使用时 TS 可识别类型 import { debounce } from "lodash"; const debouncedFn = debounce(() => console.log("debounce"), 1000); 

场景 2:为自定义 JS 工具函数写声明文件(如 utils.js):

// utils.js(JS 文件) export function formatDate(date, format) { // 日期格式化逻辑 return formattedDate; } 
// utils.d.ts(声明文件,与 utils.js 同级) declare module "./utils" { export function formatDate(date: Date | string, format: string): string; } // 使用时 TS 可识别类型 import { formatDate } from "./utils"; formatDate(new Date(), "YYYY-MM-DD"); // 正确 formatDate(123, "YYYY-MM-DD"); // 错误(TS 报错,date 需为 Date 或 string) 

13. 如何在 TypeScript 中处理异步函数的类型(如 Promise)?请举例说明。

异步函数(API 请求)是实习必备,需讲清“Promise 泛型”“async/await 类型推断”“错误处理”:

  • 核心原则:异步函数的返回值是 Promise<T> 类型,T 是异步操作成功后返回的数据类型(如 API 返回的用户数据类型)。
  • 关键说明
    1. Promise<T> 中的 T 必须与异步操作成功后的返回值类型一致(如 fetchUsers 成功返回 User[],故为 Promise<User[]>)。
    2. async 函数的返回值默认是 Promise<void>(若无 return),若有 return 值,TS 会自动推断为 Promise<返回值类型>

实习常用例子(API 请求):```
// 1. 定义 API 返回数据的类型(如用户列表)
interface User {
id: string;
name: string;
age: number;
}// 2. 定义异步函数:获取用户列表(返回 Promise<User[]>)
function fetchUsers(): Promise<User[]> {
// fetch 返回 Promise,需通过 .json() 解析为 User[]
return fetch(“https://api.example.com/users”)
.then((response) => {
if (!response.ok) {
throw new Error(“请求失败”); // 错误处理
}
// 解析 JSON 数据,断言为 User[](告知 TS 数据类型)
return response.json() as Promise<User[]>;
})
.catch((error) => {
console.error(“获取用户失败:”, error);
throw error; // 重新抛出错误,让调用方处理
});
}// 3. 用 async/await 调用(TS 自动推断类型)
async function getUsersData(): Promise {
try {
const users = await fetchUsers(); // TS 推断 users 为 User[]
console.log(users[0].name); // 正确(可安全访问 User 的属性)
} catch (error) {
console.error(“处理错误:”, error);
}
}// 调用函数
getUsersData();

14. 什么是索引签名(Index Signature)?它的作用是什么?请举例说明。

索引签名用于“定义动态属性的对象”(实习中处理键值对、配置对象常用),需讲清“定义”“语法”“例子”:

  • 索引签名定义:当对象的“属性名不确定”(如属性名是动态生成的),但“属性名类型”和“属性值类型”固定时,用索引签名约束对象的键值类型,语法为 [key: KeyType]: ValueType
  • 核心作用:约束动态属性的类型,避免因属性名不确定导致的类型错误(如遍历键值对时确保值的类型)。

实习常用例子
例子 1:定义“字符串键 -> 数字值”的映射对象(如用户分数表):

// 索引签名:key 是 string 类型,value 是 number 类型 interface ScoreMap { [key: string]: number; } // 正确使用:属性名是 string,值是 number const userScores: ScoreMap = { "张三": 90, "李四": 85, "王五": 95, }; // 遍历对象(TS 推断 value 为 number) for (const username in userScores) { const score = userScores[username]; // score 类型为 number console.log(`${username}: ${score}`); } // 错误:值不是 number(TS 报错) userScores["赵六"] = "80"; // 错误(需为 number) 

例子 2:混合固定属性和动态属性(索引签名可与固定属性共存):

interface UserConfig { name: string; // 固定属性 [key: string]: string | number; // 动态属性(值支持 string 或 number) } const config: UserConfig = { name: "张三", age: 22, // 动态属性(值为 number,符合约束) address: "北京", // 动态属性(值为 string,符合约束) }; 

15. 如何在 TypeScript 中实现类的继承和多态?请举例说明。

类是 OOP 基础(实习中封装组件逻辑、工具类常用),需讲清“继承(extends)”“多态(方法重写)”“例子”:

  • 1. 类的继承(extends)
    • 语法:子类用 extends 继承父类,子类会继承父类的属性和方法(除 private 成员)。
    • 关键:用 super() 在子类构造函数中调用父类构造函数。
  • 2. 多态
    • 定义:子类重写(override)父类的方法,使不同子类的同一方法有不同实现(需父类方法用 abstract 或普通方法,子类用 override 关键字显式重写)。

实习常用例子(动物类继承)

// 1. 定义父类:Animal(抽象类,不能实例化,仅用于继承) abstract class Animal { // protected 属性:仅父类和子类可访问 protected name: string; // 父类构造函数 constructor(name: string) { this.name = name; } // 抽象方法:父类不实现,子类必须重写(多态的核心) abstract makeSound(): void; // 普通方法:子类可继承或重写 eat(): void { console.log(`${this.name} 在吃东西`); } } // 2. 定义子类:Dog(继承 Animal) class Dog extends Animal { // 子类构造函数:必须调用 super() constructor(name: string) { super(name); // 调用父类构造函数,传入 name } // 重写父类的抽象方法(多态实现) override makeSound(): void { console.log(`${this.name} 汪汪叫`); } // 子类新增方法 fetch(): void { console.log(`${this.name} 在捡球`); } } // 3. 定义子类:Cat(继承 Animal) class Cat extends Animal { constructor(name: string) { super(name); } // 重写父类的抽象方法(多态实现:与 Dog 不同的逻辑) override makeSound(): void { console.log(`${this.name} 喵喵叫`); } } // 4. 使用:多态的体现(同一方法,不同子类有不同行为) function letAnimalSound(animal: Animal): void { animal.makeSound(); // 调用子类重写的方法(Dog 汪汪叫,Cat 喵喵叫) animal.eat(); // 调用父类继承的方法 } const dog = new Dog("旺财"); const cat = new Cat("咪宝"); letAnimalSound(dog); // 输出:"旺财 汪汪叫"、"旺财 在吃东西" letAnimalSound(cat); // 输出:"咪宝 喵喵叫"、"咪宝 在吃东西" dog.fetch(); // 调用子类新增方法:"旺财 在捡球" 

16. TypeScript 中的 readonly 和 const 的区别是什么?请举例说明。

两者均“只读”,但作用对象不同(实习中易混淆),需对比“作用范围”“修改限制”“例子”:

特性readonlyconst
作用对象类的属性、接口的属性变量(let/var 替换为 const)
作用阶段编译阶段(TS 类型校验)编译阶段(JS 语法层面)
修改限制仅限制“属性重新赋值”(对象属性内部可改)限制“变量重新赋值”(若变量是对象,内部属性可改)
使用场景定义不可重新赋值的类/接口属性定义不可重新赋值的变量
  • 例子对比

const 的使用(变量):

// 基础类型变量:不能重新赋值 const age: number = 22; age = 23; // 错误(const 变量不能重新赋值) // 对象变量:变量不能重新赋值,但对象内部属性可修改 const user: { id: string; name: string } = { id: "123", name: "张三" }; user.name = "李四"; // 正确(对象内部属性可修改) user = { id: "456", name: "王五" }; // 错误(const 变量不能重新赋值) 

readonly 的使用(类属性):

class User { readonly id: string; // 类的只读属性 name: string; constructor(id: string, name: string) { this.id = id; // 仅能在构造函数中赋值 this.name = name; } } const user = new User("123", "张三"); user.name = "李四"; // 正确(非只读属性可修改) user.id = "456"; // 错误(readonly 属性不能重新赋值) 

17. 什么是条件类型(Conditional Types)?请举例说明它的使用场景。

条件类型是“基于条件推断类型”的语法(实习中写工具类型、复用类型常用),需讲清“定义”“语法”“例子”:

  • 条件类型定义:类似 JS 的三元运算符(condition ? a : b),但作用于类型层面,根据“类型是否满足某个条件”动态生成类型,语法为 T extends U ? X : Y(若 T 是 U 的子类型,则为 X 类型,否则为 Y 类型)。
  • 核心作用:实现“类型的动态判断与生成”,常用于封装通用工具类型(如“如果是数组,取数组元素类型;否则取原类型”)。

实习常用例子
例子 1:定义“获取数组元素类型”的工具类型(若输入是数组,返回元素类型;否则返回原类型):

// 条件类型:T 是数组则返回 T[number](数组元素类型),否则返回 T type ElementOf<T> = T extends Array<infer U> ? U : T; // 使用 1:输入是数组类型,返回元素类型 type StrArr = string[]; type StrType = ElementOf<StrArr>; // StrType 为 string(数组元素类型) // 使用 2:输入是非数组类型,返回原类型 type Num = number; type NumType = ElementOf<Num>; // NumType 为 number(原类型) // 使用 3:实际场景(处理 API 返回数据,可能是数组或单个对象) interface User { id: string; name: string; } // API 返回数据类型:可能是 User[] 或 User type ApiResponse = User[] | User; // 获取最终数据类型(数组则取元素类型,否则取原类型) type FinalUserType = ElementOf<ApiResponse>; // FinalUserType 为 User 

例子 2:定义“排除 null/undefined”的工具类型:

// 条件类型:T 是 null/undefined 则返回 never,否则返回 T type NonNullable<T> = T extends null | undefined ? never : T; // 使用:排除类型中的 null/undefined type MaybeUser = User | null | undefined; type SafeUser = NonNullable<MaybeUser>; // SafeUser 为 User(排除了 null/undefined) 

18. 如何在 TypeScript 中定义函数的类型?包括参数类型、返回值类型、可选参数、默认参数等。

函数类型是基础(实习中写工具函数、事件处理函数必用),需覆盖“函数声明”“函数表达式”“特殊参数”:

5. 剩余参数(用 ... 接收多个参数,类型为数组)

// 剩余参数:nums 是 number 数组,接收所有后续参数 function sum(...nums: number[]): number { return nums.reduce((total, num) => total + num, 0); } sum(1, 2, 3); // 正确(返回 6) sum(1, "2"); // 错误(剩余参数需为 number 类型) 

4. 默认参数(参数赋值默认值,自动变为可选参数)

// 默认参数:age 默认值为 18(自动变为可选参数) function greetWithDefault(name: string, age: number = 18): string { return `Hello, ${name}, you are ${age} years old`; } greetWithDefault("张三"); // 正确(age 用默认值 18) greetWithDefault("李四", 22); // 正确(age 覆盖默认值) 

3. 可选参数(参数后加 ?,需放在必选参数后)

// 可选参数:age 是可选的(可传或不传) function greet(name: string, age?: number): string { if (age) { return `Hello, ${name}, you are ${age} years old`; } return `Hello, ${name}`; } greet("张三"); // 正确(age 省略) greet("李四", 22); // 正确(age 传入) 

2. 函数表达式(用类型别名定义函数类型)

// 1. 定义函数类型别名(参数类型 + 返回值类型) type AddFunc = (a: number, b: number) => number; // 2. 函数表达式:指定类型为 AddFunc const add: AddFunc = (a, b) => { return a + b; // TS 自动推断 a/b 为 number,返回值为 number }; 

1. 函数声明(直接指定参数/返回值类型)

// 语法:function 函数名(参数: 类型): 返回值类型 { ... } function add(a: number, b: number): number { return a + b; } add(1, 2); // 正确(参数类型匹配) add("1", 2); // 错误(参数 a 应为 number) 

19. TypeScript 的模块系统(import/export)与 JavaScript 的模块系统有什么区别?

模块系统是模块化开发基础(实习中拆分组件/工具类常用),需讲清“TS 对 JS 模块的扩展”:

  • 1. 核心共同点
    • 均支持 ES 模块(import/export)和 CommonJS 模块(require/module.exports),语法一致。
    • 均通过模块隔离代码(避免全局变量污染)。
  • 2. TS 模块系统的扩展(核心区别)
    1. 支持“类型导出/导入”
      • JS 仅能导出/导入“值”(变量、函数、对象等);
      • TS 可额外导出/导入“类型”(接口、类型别名、泛型等),用 export type/import type 语法(明确区分类型和值,优化编译)。
    2. 模块解析增强
      • 导入时可简化路径:import { User } from "@/types"(无需写相对路径 ../types)。
    3. 类型检查
      • TS 导入模块时会检查“导入的类型是否存在”(如导入不存在的类型会报错);
      • JS 仅在运行时才会发现导入错误(如导入不存在的函数)。

TS 支持更灵活的模块解析(如 baseUrlpaths 配置,可简化导入路径),需在 tsconfig.json 中配置:```
{
“compilerOptions”: {
“baseUrl”: “./src”, // 基础路径
“paths”: {
“@/“: [””] // 别名:@/ 指向 src/
}
}
}

例子:```
// 导出类型和值
export interface User { name: string } // 导出类型
export type ID = string | number; // 导出类型
export const getUserName = (user: User) => user.name; // 导出值// 导入类型和值
import { User, ID, getUserName } from “./types”; // 同时导入类型和值
import type { User as ImportedUser } from “./types”; // 仅导入类型(推荐,明确区分)

20. 实习中使用 TypeScript 时,你遇到过“类型‘X’上不存在属性‘Y’”的错误吗?如何解决?

这是实习中最常见的 TS 错误,需讲清“常见原因”“对应解决方法”“例子”,体现实战能力:

  • 常见原因及解决方法(按实习高频度排序):
    1. 原因 1:类型定义不完整(对象缺少该属性)
      • 解决:补充类型定义(如接口/类型别名中添加该属性)。
    2. 原因 2:类型推断错误(TS 推断的类型与实际类型不符)
      • 解决:用类型断言指定实际类型,或显式标注变量类型。
    3. 原因 3:使用 any/unknown 类型未处理
      • 解决:any 改为更具体的类型;unknown 需先断言为具体类型。
    4. 原因 4:联合类型未缩小范围
      • 解决:用类型守卫缩小联合类型范围,确保访问的属性在当前类型中存在。

例子:```
// 错误场景:User | string 联合类型,直接访问 name 属性报错
type UserOrStr = User | string;
const value: UserOrStr = { name: “张三”, age: 22 };console.log(value.name); // 错误(类型 UserOrStr 上不存在属性 name,因可能是 string)// 解决:用类型守卫缩小范围
if (typeof value !== “string”) {
console.log(value.name); // 正确(TS 推断 value 为 User)
}

例子:```
// 错误场景:any 类型变量赋值后,TS 无法推断后续类型
let data: any = { name: “张三”, age: 22 };
data = “hello”; // 意外赋值为 string
console.log(data.age); // 错误(string 类型无 age 属性)// 解决:显式指定 data 类型为 User
interface User {
name: string;
age: number;
}let data: User = { name: “张三”, age: 22 };
data = “hello”; // 错误(TS 提前报错,避免后续问题)

例子(DOM 元素类型推断错误):```
// 错误场景:TS 推断 getElementById 返回 HTMLElement,无 value 属性
const input = document.getElementById(“username”);
console.log(input.value); // 错误(类型 HTMLElement 上不存在属性 value)// 解决:断言为 HTMLInputElement(实际类型)
const input = document.getElementById(“username”) as HTMLInputElement;
console.log(input.value); // 正确

例子:```
// 错误场景:User 接口无 age 属性,访问 user.age 报错
interface User {
name: string;
}const user: User = { name: “张三”, age: 22 }; // 错误(User 无 age 属性)
console.log(user.age); // 错误(类型 User 上不存在属性 age)// 解决:补充 age 属性到 User 接口
interface User {
name: string;
age: number; // 新增 age 属性
}const user: User = { name: “张三”, age: 22 }; // 正确
console.log(user.age); // 正确

21. 什么是映射类型(Mapped Types)?常用的内置映射类型有哪些?请举例说明。

映射类型是“批量创建类型”的语法(实习中复用类型、修改类型常用),需讲清“定义”“内置类型”“例子”:

  • 映射类型定义:基于已有类型的“属性键”批量生成新类型,语法为 { [P in K]: T }P 是属性键占位符,K 是属性键集合,T 是属性值类型),核心是“遍历已有类型的属性,修改属性的类型或特性”。
  • 常用内置映射类型(TS 内置,实习高频):
    1. Partial<T>:将 T 的所有属性变为可选属性。
      • 场景:定义“部分更新”的参数类型(如 API PATCH 请求,仅传需要修改的属性)。
    2. Required<T>:将 T 的所有属性变为必选属性(与 Partial 相反)。
    3. Readonly<T>:将 T 的所有属性变为只读属性。
      • 场景:定义不可修改的配置对象。
    4. Pick<T, K>:从 T 中“挑选”指定属性 K 组成新类型(K 必须是 T 的属性键)。
      • 场景:提取类型中的部分属性(如从 User 中提取“姓名和年龄”)。
    5. Omit<T, K>:从 T 中“排除”指定属性 K 组成新类型(与 Pick 相反)。

例子:```
// 从 User 中排除 address 属性
type UserWithoutAddress = Omit<User, “address”>;
// UserWithoutAddress 等价于:{ name: string; age: number }

例子:```
interface User {
name: string;
age: number;
address: string;
}// 从 User 中挑选 name 和 age 属性
type UserNameAndAge = Pick<User, “name” | “age”>;
// UserNameAndAge 等价于:{ name: string; age: number }

例子:```
interface Config {
apiUrl: string;
timeout: number;
}type ReadonlyConfig = Readonly;
// ReadonlyConfig 等价于:{ readonly apiUrl: string; readonly timeout: number }const config: ReadonlyConfig = { apiUrl: “https://api.com”, timeout: 5000 };
config.apiUrl = “https://new-api.com”; // 错误(只读属性不能修改)

例子:```
interface PartialUser {
name?: string;
age?: number;
}type RequiredUser = Required;
// RequiredUser 等价于:{ name: string; age: number }

例子:```
interface User {
name: string;
age: number;
address: string;
}// Partial:所有属性变为可选
type PartialUser = Partial;
// PartialUser 等价于:{ name?: string; age?: number; address?: string }// 使用:部分更新用户信息(仅传需要修改的 name)
function updateUser(user: PartialUser): void {
// 逻辑:仅更新传入的属性
}updateUser({ name: “李四” }); // 正确(仅传 name)

22. 如何在 TypeScript 中处理 DOM 元素的类型?请举例说明常见 DOM 元素类型的使用。

操作 DOM 是实习必备(如表单、按钮交互),需讲清“常用 DOM 类型”“类型断言”“例子”:

  • 核心原则:TS 为不同 DOM 元素提供了专属类型(如 HTMLInputElementHTMLDivElement),需明确元素类型才能安全调用其属性/方法(避免 HTMLElement 类型的限制)。
  • 常用 DOM 元素类型及例子
    1. HTMLElement:所有 HTML 元素的基类(包含通用属性,如 idclassNamestyle),但无元素专属属性(如 valuesrc)。
    2. HTMLInputElement:输入框元素类型(含专属属性 valuechecked,方法 focus())。
    3. HTMLButtonElement:按钮元素类型(含专属方法 click())。
    4. HTMLSelectElement:下拉选择框类型(含专属属性 valueoptions)。
  • 关键注意事项

若无法确定元素是否存在(如动态渲染的元素),需先判断非 null,再断言类型:```
const input = document.getElementById(“username”);
if (input) {
// 非 null 后,断言为 HTMLInputElement
const typedInput = input as HTMLInputElement;
typedInput.value = “test”;
}

例子:获取下拉框并获取选中值:```
const citySelect = document.getElementById(“city”) as HTMLSelectElement;
console.log(“选中城市:”, citySelect.value); // 正确(专属属性 value)

例子:获取按钮并绑定点击事件:```
const submitBtn = document.getElementById(“submit”) as HTMLButtonElement;
submitBtn.addEventListener(“click”, () => {
console.log(“按钮被点击”);
});
submitBtn.click(); // 正确(专属方法 click)

例子:获取输入框并操作 value:```
// 断言为 HTMLInputElement(因 getElementById 返回 HTMLElement)
const usernameInput = document.getElementById(“username”) as HTMLInputElement;
usernameInput.value = “[email protected]”; // 正确(专属属性 value)
usernameInput.focus(); // 正确(专属方法 focus)

例子:获取 div 元素(无专属属性,用 HTMLElement):```
const div = document.getElementById(“container”) as HTMLElement;
div.className = “active”; // 正确(HTMLElement 有 className 属性)

23. 什么是 TypeScript 的“严格模式”(strict: true)?开启后会启用哪些关键规则?

严格模式是 TS 类型安全的核心(公司项目普遍开启),需讲清“定义”“关键规则”“作用”:

  • 严格模式定义:在 tsconfig.json 中设置 compilerOptions.strict: true,开启后会启用一组“严格的类型检查规则”,强制开发者编写更严谨的类型代码,减少潜在的类型错误(是 TS 推荐的最佳实践)。
  • 开启后启用的关键规则(实习高频,需重点说明):
    1. noImplicitAny:禁止隐式 any 类型(变量/参数未指定类型且 TS 无法推断时,报错)。
      • 作用:避免因 any 丢失类型检查(如函数参数未指定类型,TS 不再默认视为 any)。
    2. strictNullChecks:严格检查 nullundefinednull/undefined 不能赋值给其他类型,除非显式包含)。
      • 作用:避免“空指针错误”(如访问 null.value),是最实用的规则之一。
    3. strictFunctionTypes:严格检查函数参数类型(函数参数类型必须精确匹配,不能是父类型)。
      • 作用:避免函数参数类型不匹配导致的逻辑错误。
    4. strictPropertyInitialization:严格检查类属性的初始化(类的非可选属性必须在构造函数中初始化,或用 ! 显式标记为“后续初始化”)。
      • 作用:避免类属性未初始化就使用。
  • 实习建议:开发时务必开启严格模式(即使是个人项目),养成严谨的类型习惯,面试中提及“熟悉严格模式及关键规则”会加分。

例子:```
class User {
name: string; // 非可选属性
age?: number; // 可选属性(无需初始化)constructor(name: string) {
this.name = name; // 正确(构造函数中初始化)
}
}// 错误(name 未在构造函数中初始化,且无 ! 标记)
class BadUser {
name: string;
constructor() {}
}

例子:```
type AddFunc = (a: number, b: number) => number;
const add: AddFunc = (a: number, b: number) => a + b; // 正确(参数类型完全匹配)// 错误(参数 b 为 any,与 AddFunc 的 number 不匹配)
const badAdd: AddFunc = (a: number, b: any) => a + b;

例子:```
// 错误(开启 strictNullChecks 后,string 类型不能接收 null)
let name: string = null; // 错误(Type ‘null’ is not assignable to type ‘string’)// 正确(显式允许 null)
let name: string | null = null;
if (name) {
console.log(name.length); // 正确(非 null 后才能访问 length)
}

例子:```
// 错误(开启 noImplicitAny 后,参数 a 隐式为 any,报错)
function add(a, b) {
return a + b;
}// 正确(显式指定参数类型)
function add(a: number, b: number): number {
return a + b;
}

24. 如何在 TypeScript 中实现泛型约束(Generic Constraints)?请举例说明它的作用。

泛型约束是“限制泛型范围”的语法(避免泛型过于宽泛,确保有特定属性/方法),需讲清“定义”“语法”“例子”:

  • 泛型约束定义:默认情况下,泛型 T 可以是任意类型,若需限制 T 必须包含某个属性/方法(如“T 必须有 length 属性”),需用 T extends U 语法(U 是约束类型,T 必须是 U 的子类型),这就是泛型约束。
  • 核心作用:避免泛型过于灵活导致的错误(如调用泛型变量的 length 方法,但 T 可能是 number 类型,无 length),确保泛型变量有所需的属性/方法。

实习常用例子
例子 1:定义“获取有 length 属性的变量的长度”的泛型函数(约束 T 必须有 length 属性):

// 1. 定义约束类型:有 length 属性的类型 interface HasLength { length: number; } // 2. 泛型约束:T 必须是 HasLength 的子类型(即 T 必须有 length 属性) function getLength<T extends HasLength>(value: T): number { return value.length; // 正确(因 T 有 length 属性,不会报错) } // 3. 使用:传入有 length 属性的类型(正确) getLength("hello"); // 5(string 有 length) getLength([1, 2, 3]); // 3(数组有 length) getLength({ length: 10 }); // 10(对象有 length 属性) // 错误:传入无 length 属性的类型(number 无 length) getLength(123); // 错误(Type 'number' does not satisfy the constraint 'HasLength') 

例子 2:定义“获取对象指定属性值”的泛型函数(约束“属性必须是对象的键”):

// 泛型约束:K 必须是 T 的属性键(keyof T 是 T 的所有属性键组成的联合类型) function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; // 正确(K 是 T 的属性键,不会访问不存在的属性) } // 使用: const user = { name: "张三", age: 22 }; getProperty(user, "name"); // "张三"(正确,name 是 user 的属性) getProperty(user, "age"); // 22(正确,age 是 user 的属性) // 错误:key 不是 user 的属性 getProperty(user, "address"); // 错误(Argument of type '"address"' is not assignable to parameter of type '"name" | "age"') 

25. 实习中使用 TypeScript 时,你遇到过哪些印象深刻的问题?是如何解决的?(项目经验类,必问)

这类问题考察实战能力,需结合实习场景(如 API 类型、第三方库、DOM 操作),讲清“问题场景”“解决过程”“收获”,避免空泛:

  • 面试回答示例(结合真实实习场景)
    “在实习中,我遇到过两个印象较深的 TS 问题,都是在开发 Vue 组件时遇到的:第一个问题是API 返回数据类型不匹配。当时我负责用户列表组件,定义了 User 接口(包含 idnameage),但调用 API 后,TS 报错‘类型“undefined”不能赋值给类型“number”’。排查后发现,API 返回的 age 字段在部分用户数据中是 undefined(因用户未填写年龄),但我定义的 User 接口中 age 是必选的 number 类型,导致类型不匹配。第二个问题是第三方 JS 库无 TypeScript 类型。当时项目需要引入一个老的日期格式化 JS 库(date-format-utils.js),但该库无官方类型声明,导入后 TS 报错‘无法找到模块“date-format-utils”的声明文件’。这两个问题让我明白:TS 问题的核心是‘类型匹配’,遇到错误时先定位‘实际类型’与‘声明类型’的差异,再针对性调整类型定义;同时
    续接第25题的回答:
    • 解决过程:
      1. 先检查 API 文档,确认 age 是可选字段(可能为 undefined);
      2. 修改 User 接口,将 age 改为可选属性(age?: number);
      3. 在组件中使用 age 时,添加空值判断(如 user.age || 0),避免渲染错误。
    • 解决过程:
      1. 先尝试安装官方声明文件(npm install @types/date-format-utils --save-dev),但发现不存在;
      2. 手动创建声明文件 date-format-utils.d.ts,在文件中声明该模块的类型(如 declare module "date-format-utils" { export function format(date: Date, pattern: string): string; });
      3. 导入库时,TS 能识别声明的类型,可安全调用 format 方法,且有智能提示。

同时,对于第三方库的类型问题,优先使用官方声明文件,若无则通过自定义声明文件补充,这既保证了类型安全,也提升了开发效率。这些经历让我更深刻地理解了TypeScript“类型即契约”的设计理念,在后续开发中会更注重类型定义的准确性和前瞻性。

26. TypeScript 中的“类型推断”是指什么?请举例说明常见的类型推断场景。

类型推断是TS的核心特性(减少手动类型标注),需讲清“定义”“场景”“例子”:

  • 类型推断定义:TS在未显式指定类型时,自动根据变量的初始化值、函数的返回值等信息推断出变量/参数/返回值的类型,简化代码的同时保持类型安全。
  • 常见类型推断场景

泛型类型推断(调用泛型函数时自动推断类型参数):

function identity<T>(value: T): T { return value; } const str = identity("hello"); // 推断 T 为 string,str 类型为 string const num = identity(123); // 推断 T 为 number,num 类型为 number 

函数参数类型上下文推断(结合函数类型):

type LogFunc = (message: string) => void; const log: LogFunc = (msg) => { // TS 推断 msg 为 string 类型(因 LogFunc 约束参数为 string) console.log(msg); }; 

数组和对象推断

// 数组:推断为 string[] 类型 const fruits = ["apple", "banana", "orange"]; // 对象:推断为 { name: string; age: number } 类型 const user = { name: "张三", age: 22 }; 

函数返回值推断(无需显式指定返回值类型):

// TS 推断返回值为 number 类型 function add(a: number, b: number) { return a + b; // 返回值是 number,故函数返回值类型为 number } 

变量初始化推断(最基础):

let username = "张三"; // TS 推断 username 为 string 类型 let age = 22; // 推断为 number 类型 let isStudent = true; // 推断为 boolean 类型 

27. 如何在 TypeScript 中定义“函数重载”?请举例说明其使用场景。

函数重载用于“同一函数支持多种参数类型/个数”(实习中处理灵活入参常用),需讲清“定义”“语法”“例子”:

  • 函数重载定义:允许为同一函数定义多个“函数签名”(不同的参数类型/个数/返回值类型),再提供一个统一的实现,使函数能根据不同入参自动匹配对应的签名,提升类型准确性。
  • 语法规则
    1. 先定义多个函数签名(仅声明参数和返回值类型,无实现);
    2. 最后定义一个“实现函数”(参数类型需兼容所有签名,通常用联合类型)。
    3. 方式1:传入 Date 对象,返回默认格式(YYYY-MM-DD);
    4. 方式2:传入 Date 对象 + 自定义格式字符串,返回自定义格式。
  • 关键注意事项
    • 实现函数的参数类型必须“兼容所有签名”(如例子中 format 为可选参数,兼容签名1的无参数和签名2的有参数);
    • 调用函数时,TS 会根据入参匹配最精确的签名,提供对应类型提示。

实习常用场景(处理多种入参格式)
例子:定义“格式化日期”的函数,支持两种调用方式:

// 1. 定义函数重载签名(两种调用方式) function formatDate(date: Date): string; // 签名1:仅传 date function formatDate(date: Date, format: string): string; // 签名2:传 date + format // 2. 实现函数(参数类型兼容所有签名,用联合类型) function formatDate(date: Date, format?: string): string { if (format) { // 自定义格式逻辑(简化示例) return `自定义格式:${date.toISOString()} ${format}`; } else { // 默认格式逻辑(YYYY-MM-DD) return date.toISOString().split("T")[0]; } } // 3. 使用:TS 自动匹配对应的签名 const defaultFormatted = formatDate(new Date()); // 匹配签名1,返回 string const customFormatted = formatDate(new Date(), "YYYY/MM/DD"); // 匹配签名2,返回 string 

28. TypeScript 中的“命名空间(Namespace)”是什么?它与模块(Module)的区别是什么?

命名空间用于“组织代码、避免命名冲突”(实习中较少用,但需了解),需讲清“定义”“区别”:

  • 实习建议:现代前端项目(如Vue/React+TS)中,优先使用模块(import/export)组织代码,命名空间仅在维护旧项目时可能用到。

与模块(Module)的核心区别

特性命名空间(Namespace)模块(Module)
文件关联可在单个文件中定义,支持跨文件合并每个文件就是一个独立模块
依赖管理无内置依赖管理,需手动通过 <reference> 引入支持 import/export 管理依赖
作用域全局作用域内的一个容器(可能污染全局)独立作用域(文件内声明默认不暴露)
现代项目适用性适用于早期非模块化项目(如全局脚本)适用于现代模块化项目(推荐使用)

命名空间定义:用 namespace 关键字定义,用于将相关的类型、函数、变量等封装在一个命名空间内,通过 export 暴露内部成员,避免全局命名冲突,语法:

// 定义命名空间(可嵌套) namespace MathUtils { export function add(a: number, b: number): number { return a + b; } export function multiply(a: number, b: number): number { return a * b; } // 未 export 的成员仅在命名空间内可见 function subtract(a: number, b: number): number { return a - b; } } // 使用命名空间成员(通过 命名空间.成员 访问) MathUtils.add(1, 2); // 3 MathUtils.multiply(2, 3); // 6 

29. 如何在 TypeScript 中定义“抽象类(Abstract Class)”和“抽象方法(Abstract Method)”?它们的作用是什么?

抽象类是“不能实例化的基类”(用于定义子类的公共接口),需讲清“定义”“作用”“例子”:

  • 抽象类与抽象方法定义
    • 抽象类:用 abstract 关键字修饰的类,不能直接实例化,仅用于被继承。
    • 抽象方法:抽象类中用 abstract 关键字修饰的方法,只有声明、没有实现,子类必须重写该方法。
  • 核心作用
    1. 定义“类的模板”(规定子类必须实现的方法),确保子类结构一致;
    2. 封装子类的公共逻辑(抽象类可包含普通方法和属性,子类继承后直接使用)。
  • 关键注意事项
    • 抽象类不能直接实例化(new BaseComponent("test") 会报错);
    • 子类必须重写所有抽象方法(否则子类也需声明为抽象类)。

实习常用例子(定义组件基类)

// 1. 定义抽象类(组件基类) abstract class BaseComponent { // 公共属性(子类继承) protected name: string; // 构造函数(子类需调用 super()) constructor(name: string) { this.name = name; } // 普通方法(子类继承后可直接使用) public logName(): void { console.log(`组件名称:${this.name}`); } // 抽象方法(子类必须重写) public abstract render(): string; // 声明渲染方法,无实现 // 抽象方法(带参数和返回值) public abstract update(data: unknown): boolean; } // 2. 定义子类(继承抽象类,必须实现所有抽象方法) class ButtonComponent extends BaseComponent { constructor(name: string) { super(name); // 调用父类构造函数 } // 实现抽象方法 render public override render(): string { return `<button>${this.name}</button>`; } // 实现抽象方法 update public override update(data: { text: string }): boolean { this.name = data.text; return true; } } // 3. 使用:实例化子类(抽象类不能实例化) const button = new ButtonComponent("提交按钮"); button.logName(); // 输出:"组件名称:提交按钮" console.log(button.render()); // 输出:"<button>提交按钮</button>" button.update({ text: "确认按钮" }); // 正确(实现了抽象方法) 

30. TypeScript 中,如何处理“循环依赖”问题?请举例说明常见解决方案。

循环依赖指“模块A依赖模块B,模块B同时依赖模块A”(实习中拆分模块时易出现),需讲清“问题表现”“解决方案”:

  • 问题表现
    • 编译时可能报错“Cannot access ‘XXX’ before initialization”;
    • 运行时可能出现变量/类型未定义(因模块加载顺序冲突)。
  • 常见解决方案(按实习实用性排序):
    1. 提取公共类型到独立模块(最推荐):
      • 场景:A和B因共享类型相互依赖,将共享类型提取到 types.ts,A和B均依赖 types.ts,消除直接依赖。
    2. 使用“延迟导入”(动态 import)
      • 场景:仅在函数内部使用依赖,通过动态 import() 延迟加载,避免模块初始化阶段的依赖冲突。
    3. 调整模块设计,消除不必要依赖
      • 分析依赖关系,合并或拆分模块,确保依赖链是单向的(如A→B→C,而非A↔B)。

例子:```
// A.ts(依赖 B.ts)
import { funcB } from “./B”;
export function funcA() {
return funcB();
}// B.ts(需使用 A.ts 的 funcA,但改为动态导入)
export async function funcB() {
// 动态导入:在函数内部才加载 A.ts,避免初始化阶段循环依赖
const { funcA } = await import(“./A”);
return funcA() + " from B";
}

例子:```
// types.ts(提取公共类型)
export interface User {
id: string;
name: string;
}// A.ts(依赖 types.ts,不直接依赖 B.ts)
import { User } from “./types”;
export function formatUser(user: User): string {
return ${user.id}: ${user.name};
}// B.ts(依赖 types.ts,不直接依赖 A.ts)
import { User } from “./types”;
export function createUser(name: string): User {
return { id: Date.now().toString(), name };
}

31. 什么是“字面量类型(Literal Types)”?它与普通类型有什么区别?请举例说明。

字面量类型是“具体值的类型”(比普通类型更精确),需讲清“定义”“类型”“例子”:

  • 字面量类型定义:表示“具体的单一值”的类型(如 10"hello"true),而普通类型(如 numberstring)表示“一类值”。例如,10 是字面量类型(仅匹配值 10),number 是普通类型(匹配所有数字)。
  • 常见字面量类型
    1. 字符串字面量类型:如 "primary""success"(仅匹配特定字符串)。
    2. 数字字面量类型:如 12(仅匹配特定数字)。
    3. 布尔字面量类型truefalse(仅匹配特定布尔值)。
  • 实习常用场景:定义固定选项(如按钮类型、状态码、性别等),比枚举更轻量,常用于联合类型中限制取值范围。

与普通类型的区别及例子

// 普通类型:string 可匹配任何字符串 let str: string = "primary"; str = "success"; // 正确 // 字符串字面量类型:仅匹配 "primary" let primaryStr: "primary" = "primary"; primaryStr = "success"; // 错误(Type '"success"' is not assignable to type '"primary"') // 结合联合类型:限制取值范围(常用场景) type ButtonType = "primary" | "secondary" | "danger"; // 仅允许这三个值 const btnType: ButtonType = "primary"; // 正确 const invalidBtnType: ButtonType = "warning"; // 错误(不在允许范围内) // 数字字面量类型:限制为特定数字 type StatusCode = 200 | 400 | 500; const code: StatusCode = 200; // 正确 const errorCode: StatusCode = 404; // 错误(不在允许范围内) 

32. TypeScript 中,infer 关键字的作用是什么?请举例说明其使用场景。

infer 用于“在条件类型中推断类型”(高级特性,实习中写工具类型常用),需讲清“定义”“例子”:

  • infer 作用:在条件类型(T extends ... ? X : Y)中,用于“推断出一个类型变量”(类似函数中的参数),并在条件分支中使用该推断出的类型,简化类型提取逻辑。

实习常用场景(提取类型中的部分信息)
例子 1:提取函数的返回值类型:

// 条件类型:若 T 是函数,则推断其返回值类型 R,否则返回 T type ReturnType<T> = T extends (...args: any[]) => infer R ? R : T; // 使用:提取函数的返回值类型 function getUser() { return { id: "123", name: "张三" }; } type UserReturnType = ReturnType<typeof getUser>; // UserReturnType 等价于 { id: string; name: string }(函数返回值类型) 

例子 2:提取数组的元素类型:

// 条件类型:若 T 是数组,则推断其元素类型 U,否则返回 T type ElementType<T> = T extends (infer U)[] ? U : T; // 使用: type StrArr = string[]; type StrElement = ElementType<StrArr>; // string(数组元素类型) type Num = number; type NumElement = ElementType<Num>; // number(非数组,返回原类型) 

例子 3:提取 Promise 的 resolve 类型:

// 条件类型:若 T 是 Promise,则推断其 resolve 类型 U,否则返回 T type PromiseType<T> = T extends Promise<infer U> ? U : T; // 使用: type UserPromise = Promise<{ id: string; name: string }>; type User = PromiseType<UserPromise>; // { id: string; name: string }(Promise resolve 类型) 

33. 如何在 TypeScript 中定义“全局变量”的类型?请举例说明。

全局变量(如window上的自定义属性)的类型定义是实习常见需求,需讲清“声明方式”:

  • 核心方法:通过“全局声明”(在 .d.ts 文件中扩展全局命名空间),告知TS全局变量的类型。

实习常用例子
场景 1:为 window 对象添加自定义属性 appConfig

// 1. 创建全局声明文件(如 global.d.ts,放在项目根目录) declare global { interface Window { appConfig?: { apiUrl: string; env: "development" | "production"; }; } } // 2. 在代码中使用(TS 可识别 window.appConfig 的类型) if (window.appConfig) { console.log("API 地址:", window.appConfig.apiUrl); // 正确(有类型提示) if (window.appConfig.env === "development") { console.log("开发环境"); } } 

场景 2:定义全局变量 VERSION(如构建时注入的版

2025开年,AI技术打得火热,正在改变前端人的职业命运:

阿里云核心业务全部接入Agent体系;

字节跳动30%前端岗位要求大模型开发能力;

腾讯、京东、百度开放招聘技术岗,80%与AI相关……

大模型正在重构技术开发范式,传统CRUD开发模式正在被AI原生应用取代!

最残忍的是,业务面临转型,领导要求用RAG优化知识库检索,你不会;带AI团队,微调大模型要准备多少数据,你不懂;想转型大模型应用开发工程师等相关岗,没项目实操经验……这不是技术焦虑,而是职业生存危机!

曾经React、Vue等热门的开发框架,已不再是就业的金钥匙。如果认为会调用API就是懂大模型、能进行二次开发,那就大错特错了。制造、医疗、金融等各行业都在加速AI应用落地,未来企业更看重能用AI大模型技术重构业务流的技术人。

如今技术圈降薪裁员频频爆发,传统岗位大批缩水,相反AI相关技术岗疯狂扩招,薪资逆势上涨150%,大厂老板们甚至开出70-100W年薪,挖掘AI大模型人才!

在这里插入图片描述

不出1年 “有AI项目开发经验”或将成为前端人投递简历的门槛。

风口之下,与其像“温水煮青蛙”一样坐等被行业淘汰,不如先人一步,掌握AI大模型原理+应用技术+项目实操经验,“顺风”翻盘!

大模型目前在人工智能领域可以说正处于一种“炙手可热”的状态,吸引了很多人的关注和兴趣,也有很多新人小白想要学习入门大模型,那么,如何入门大模型呢?

下面给大家分享一份2025最新版的大模型学习路线,帮助新人小白更系统、更快速的学习大模型!

2025最新版ZEEKLOG大礼包:《AGI大模型学习资源包》免费分享**

一、2025最新大模型学习路线

一个明确的学习路线可以帮助新人了解从哪里开始,按照什么顺序学习,以及需要掌握哪些知识点。大模型领域涉及的知识点非常广泛,没有明确的学习路线可能会导致新人感到迷茫,不知道应该专注于哪些内容。

我们把学习路线分成L1到L4四个阶段,一步步带你从入门到进阶,从理论到实战。

L1级别:AI大模型时代的华丽登场

L1阶段:我们会去了解大模型的基础知识,以及大模型在各个行业的应用和分析;学习理解大模型的核心原理,关键技术,以及大模型应用场景;通过理论原理结合多个项目实战,从提示工程基础到提示工程进阶,掌握Prompt提示工程。

L2级别:AI大模型RAG应用开发工程

L2阶段是我们的AI大模型RAG应用开发工程,我们会去学习RAG检索增强生成:包括Naive RAG、Advanced-RAG以及RAG性能评估,还有GraphRAG在内的多个RAG热门项目的分析。

L3级别:大模型Agent应用架构进阶实践

L3阶段:大模型Agent应用架构进阶实现,我们会去学习LangChain、 LIamaIndex框架,也会学习到AutoGPT、 MetaGPT等多Agent系统,打造我们自己的Agent智能体;同时还可以学习到包括Coze、Dify在内的可视化工具的使用。

L4级别:大模型微调与私有化部署

L4阶段:大模型的微调和私有化部署,我们会更加深入的探讨Transformer架构,学习大模型的微调技术,利用DeepSpeed、Lamam Factory等工具快速进行模型微调;并通过Ollama、vLLM等推理部署框架,实现模型的快速部署。

整个大模型学习路线L1主要是对大模型的理论基础、生态以及提示词他的一个学习掌握;而L3 L4更多的是通过项目实战来掌握大模型的应用开发,针对以上大模型的学习路线我们也整理了对应的学习视频教程,和配套的学习资料。

二、大模型经典PDF书籍

书籍和学习文档资料是学习大模型过程中必不可少的,我们精选了一系列深入探讨大模型技术的书籍和学习文档,它们由领域内的顶尖专家撰写,内容全面、深入、详尽,为你学习大模型提供坚实的理论基础(书籍含电子版PDF)

三、大模型视频教程

对于很多自学或者没有基础的同学来说,书籍这些纯文字类的学习教材会觉得比较晦涩难以理解,因此,我们提供了丰富的大模型视频教程,以动态、形象的方式展示技术概念,帮助你更快、更轻松地掌握核心知识

四、大模型项目实战

学以致用 ,当你的理论知识积累到一定程度,就需要通过项目实战,在实际操作中检验和巩固你所学到的知识,同时为你找工作和职业发展打下坚实的基础。

五、大模型面试题

面试不仅是技术的较量,更需要充分的准备。

在你已经掌握了大模型技术之后,就需要开始准备面试,我们将提供精心整理的大模型面试题库,涵盖当前面试中可能遇到的各种技术问题,让你在面试中游刃有余。


因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

2025最新版ZEEKLOG大礼包:《AGI大模型学习资源包》免费分享

Read more

「源力觉醒 创作者计划」实测解析!文心一言 4.5 开源版本地化部署的表现与潜力

「源力觉醒 创作者计划」实测解析!文心一言 4.5 开源版本地化部署的表现与潜力

引言 2025 年 6 月 30 日,百度文心大模型 4.5 系列正式开源,并首发于 GitCode 平台!这一重磅消息在 AI 领域掀起了不小的波澜。作为国内最早布局大模型研发的企业之一,百度所推出的文心大模型目前已跻身国内顶级大模型行列,此次开源无疑将对各行各业产生深远影响,进一步加速大模型的发展进程。接下来,就让我们一同探究文心一言 4.5 开源版本地化部署的表现与潜力。 文章目录 * 引言 * 一、文心大模型 ERNIE 4.5 开源介绍 * 1.1 开源版本介绍 * 1.1 ERNIE 4.5 的主要特点和区别 * 二、文心ERNIE 4.5 技术解析 * 2.1

By Ne0inhk
GitHub Copilot AI 编程超全使用教程,从入门到精通

GitHub Copilot AI 编程超全使用教程,从入门到精通

前言 作为 GitHub 推出的 AI 编程助手,GitHub Copilot 凭借强大的代码补全、自然语言交互、自动化开发等能力,成为了开发者提升编码效率的 “神器”。它能支持主流 IDE(VS Code、IntelliJ IDEA、Eclipse 等)、终端等多环境,还可自定义配置、切换 AI 模型,适配个人和团队的不同开发需求。本文结合 GitHub 官方文档和实际使用经验,用通俗易懂的方式讲解 Copilot 的完整使用方法,从环境搭建到高级技巧,再到故障排除,一站式搞定 Copilot AI 编程! 一、GitHub Copilot 核心能力一览 在开始使用前,先快速了解 Copilot 的核心功能,清楚它能帮我们解决哪些开发问题: 1. 智能代码补全:

By Ne0inhk
VSCode Copilot 终极魔改:以智谱 GLM-4.6 为例,一文搞定任意大模型接入

VSCode Copilot 终极魔改:以智谱 GLM-4.6 为例,一文搞定任意大模型接入

VSCode Copilot 终极魔改:以智谱 GLM-4.6 为例,一文搞定任意大模型接入 前言:为何你的 Copilot 需要一次“魔改”? 本文旨在帮助所有希望突破 VSCode Copilot 模型限制、追求更高代码效率和性价比的开发者。如果你也曾面临以下困境,那么这篇文章就是为你量身打造的: * Copilot 官方模型不够用:想尝试最新、最强的国产模型(如智谱 GLM、文心一言、Kimi)却无从下手。 * API 订阅成本高:官方或其他国外模型的订阅费和按量计费(通常以美元结算)让个人开发者望而却步。 * 替代品体验有瑕疵:其他辅助插件在某些场景下不如原生的 Copilot 轻便、流畅。 本文将提供一个终极解决方案:通过一个 VSCode 插件,无缝接入任何支持 OpenAI 兼容接口的大模型。我将以当前备受瞩目的国产模型智谱 GLM-4.6 为例,

By Ne0inhk
Buzz语音转文字离线免费版安装使用(含Whisper最新模型)

Buzz语音转文字离线免费版安装使用(含Whisper最新模型)

简介: Buzz1.2.0(2024年12月24日更新的,是2025年7月最新版本) Buzz有python编写的, 在您的个人计算机上离线转录和翻译音频。由 OpenAI 的 Whisper 提供支持。 应用场景: 歌曲提取歌词,音频/视频提取文字 软件下载(windows为例): github下载地址: Release v1.2.0 · chidiwilliams/buzzhttps://github.com/chidiwilliams/buzz/releases/tag/v1.2.0 文章最后有百度云盘离线下载地址(含模型) 软件安装: exe文件直接安装即可 软件使用: 当前支持的模型: 如果没有【查看文件位置】 C:\Users\用户\AppData\Local\Buzz\Buzz\

By Ne0inhk