细节问题

46 阅读6分钟
事件循环

执行完一个宏任务后,立即清空所有微任务,然后在进行ui渲染,最后再开启下一个宏任务。

  • 1.首先script标签里代码作为宏任务开始执行。
  • 2.在执行过程中,同步代码直接在调用栈上运行
  • 3.如果遇到宏任务,就把它交给对应的webapi,并在指定时间后将其回调函数放入宏任务队列。
  • 4.如果遇到微任务,将其回调函数放入到微任务队列
  • 5.当前这个宏任务执行完毕,调用栈变空。
  • 6.事件循环立即检测微任务队列,将里面的所有微任务依次取出执行,直到微任务队列被清空。
  • 7.清空后浏览器会进行一次ui渲染
  • 8.渲染后,事件循环再回到宏任务队列,取出下一个宏任务,重复2-7步。
typescript

📌 一、基础题(语法 & 类型系统)

  1. TypeScript 和 JavaScript 的区别?
    👉 TypeScript 是 JavaScript 的超集,增加了静态类型检查、接口、枚举、泛型、装饰器等。

  2. unknownany 的区别?
    👉 any 绕过类型检查,能做任何操作;unknown 需要先做类型缩小(type narrowing)才能使用。

  3. interfacetype 的区别?

    • interface 更适合描述对象结构,可以被 extends/implements
    • type 可以定义基本类型别名、联合类型、交叉类型。
  4. enum 和字面量联合类型的区别?
    👉 enum 是运行时存在的对象;联合类型只是编译期的类型,不会生成 JS 代码。

  5. 什么是类型断言?和类型转换有什么区别?
    👉 类型断言只是在编译期告诉编译器“我确定类型”,不会真的转换值。


📌 二、进阶题(泛型 & 工具类型)

  1. 泛型是什么?为什么要用泛型?
    👉 泛型让类型像函数参数一样可复用,增强灵活性。

  2. 实现一个泛型工具类型 MyPick<T, K>

    type MyPick<T, K extends keyof T> = {
      [P in K]: T[P];
    };
    
  3. Partial<T>Required<T>Readonly<T>Record<K, T> 的作用?
    👉 都是 TypeScript 内置工具类型,用于对象属性的修饰。

  4. 如何定义一个只能接收字符串或数字的泛型函数?

    function identity<T extends string | number>(arg: T): T {
      return arg;
    }
    
  5. 解释 keyofintypeof 在 TS 中的用法。

  • keyof → 取对象的键组成联合类型。
  • in → 用在映射类型里遍历键。
  • typeof → 获取变量或函数的类型。

📌 三、类型体操(高频难点)

  1. 实现一个 Exclude<T, U>
type MyExclude<T, U> = T extends U ? never : T;
  1. 实现一个 TupleToUnion<[string, number]>"string" | "number"
type TupleToUnion<T extends any[]> = T[number];
  1. 实现一个 First<[1, 2, 3]>1
type First<T extends any[]> = T extends [infer F, ...any[]] ? F : never;
  1. 解释一下 infer 的作用?
    👉 infer 用于条件类型中,推断出某个类型并命名。
  2. 写一个 DeepReadonly<T> 工具类型。
type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};

📌 四、工程实践题

  1. 在 React 项目里,如何给 props 添加类型?
interface Props {
  title: string;
  onClick?: () => void;
}
const Button: React.FC<Props> = ({ title, onClick }) => <button>{title}</button>;
  1. 如何给 Axios 请求封装加类型?
interface User { id: number; name: string }
async function fetchUser(): Promise<User> {
  const { data } = await axios.get<User>("/api/user");
  return data;
}
  1. 如何在项目中开启严格模式?
    👉 tsconfig.json"strict": true
  2. 你在项目里遇到过哪些类型报错?是怎么解决的?
    👉 比如:类型“{}”上不存在属性“xxx”,用类型收窄或 Partial 修正。
  3. 在 Node.js 里如何用 TS 开发?
    👉 用 ts-nodeesbuild/tsup 编译,tsconfig.json 配置 moduleResolution: "node"

    📌 TypeScript 面试问答清单

🔹 一、基础部分

Q1: TypeScript 和 JavaScript 有什么区别?
👉 A: TypeScript 是 JavaScript 的超集,支持静态类型检查。JS 在运行时报错,TS 在编译期就能发现错误。TS 还增加了接口、枚举、泛型、装饰器等功能。


Q2: anyunknown 的区别是什么?
👉 A:

  • any 可以绕过所有类型检查,赋值给任何类型。
  • unknown 更安全,必须先做类型缩小(例如 typeof、类型断言)才能使用。
let a: any = 1; a.toFixed(); // OK
let b: unknown = 1; b.toFixed(); // ❌ 编译报错

Q3: interfacetype 有什么区别?
👉 A:

  • interface:更适合定义对象结构,可继承,可被类实现。
  • type:能定义联合类型、交叉类型,更灵活。
    一般建议:对象结构用 interface,复杂组合用 type

Q4: 什么是类型断言?它和类型转换的区别是什么?
👉 A:
类型断言是告诉编译器“我确定类型”,不会真的改变值。

const el = document.getElementById("app") as HTMLDivElement;

类型转换(runtime)会真的改变数据,比如 Number("123")


Q5: enum 和字面量联合类型有什么区别?
👉 A:

  • enum 是运行时存在的对象,会生成 JS 代码。
  • 联合类型只存在于编译阶段,不会生成代码,更轻量。

🔹 二、进阶部分

Q6: 什么是泛型?为什么要用泛型?
👉 A: 泛型让类型更灵活,可以复用。比如定义一个函数,它的输入和输出类型要保持一致:

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

Q7: 实现一个 MyPick<T, K> 工具类型。
👉 A:

type MyPick<T, K extends keyof T> = {
  [P in K]: T[P];
};

Q8: 解释一下 keyofintypeof 在 TS 中的作用。
👉 A:

  • keyof:取对象所有键组成联合类型。
  • in:在映射类型中遍历键。
  • typeof:获取变量或函数的类型。

Q9: 写一个只能接收字符串或数字的泛型函数。
👉 A:

function log<T extends string | number>(value: T): T {
  return value;
}

Q10: Partial<T>Required<T> 的区别?
👉 A:

  • Partial<T>:把所有属性变成可选。
  • Required<T>:把所有属性变成必填。

🔹 三、类型体操

Q11: 实现一个 Exclude<T, U>
👉 A:

type MyExclude<T, U> = T extends U ? never : T;

Q12: infer 的作用是什么?
👉 A: infer 用于条件类型中推断类型。

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

Q13: 写一个 First<[1, 2, 3]>1
👉 A:

type First<T extends any[]> = T extends [infer F, ...any[]] ? F : never;

Q14: 写一个 DeepReadonly<T>
👉 A:

type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};

Q15: 什么是条件类型?举个例子。
👉 A: 条件类型就是 T extends U ? X : Y
比如:

type IsString<T> = T extends string ? true : false;

🔹 四、工程实践

Q16: 在 React 项目里,如何给组件 Props 添加类型?
👉 A:

interface Props {
  title: string;
  onClick?: () => void;
}
const Button: React.FC<Props> = ({ title, onClick }) => <button>{title}</button>;

Q17: 如何给 Axios 请求加上类型?
👉 A:

interface User { id: number; name: string }
async function fetchUser(): Promise<User> {
  const { data } = await axios.get<User>("/api/user");
  return data;
}

Q18: 在项目中如何开启严格模式?
👉 A:tsconfig.json 中设置:

{
  "compilerOptions": {
    "strict": true
  }
}

Q19: 你在项目中遇到过哪些 TS 类型报错?怎么解决?
👉 A: 比如:

  • “类型 {} 上不存在属性 xxx” → 用 Partial<T> 或类型收窄解决。
  • “可能为 undefined” → 用 ?.if 判断。

Q20: 在 Node.js 里如何用 TS 开发?
👉 A: 常用 ts-node 直接运行,或者用 tsup/esbuild 打包,tsconfig.json 里需要配置 moduleResolution: "node"


总结:面试官通常会从 基础语法 → 泛型 & 工具类型 → 类型体操 → 工程实践 这四个层次提问。