事件循环
执行完一个宏任务后,立即清空所有微任务,然后在进行ui渲染,最后再开启下一个宏任务。
- 1.首先script标签里代码作为宏任务开始执行。
- 2.在执行过程中,同步代码直接在调用栈上运行
- 3.如果遇到宏任务,就把它交给对应的webapi,并在指定时间后将其回调函数放入宏任务队列。
- 4.如果遇到微任务,将其回调函数放入到微任务队列
- 5.当前这个宏任务执行完毕,调用栈变空。
- 6.事件循环立即检测微任务队列,将里面的所有微任务依次取出执行,直到微任务队列被清空。
- 7.清空后浏览器会进行一次ui渲染
- 8.渲染后,事件循环再回到宏任务队列,取出下一个宏任务,重复2-7步。
typescript
📌 一、基础题(语法 & 类型系统)
-
TypeScript 和 JavaScript 的区别?
👉 TypeScript 是 JavaScript 的超集,增加了静态类型检查、接口、枚举、泛型、装饰器等。 -
unknown和any的区别?
👉any绕过类型检查,能做任何操作;unknown需要先做类型缩小(type narrowing)才能使用。 -
interface和type的区别?interface更适合描述对象结构,可以被extends/implements。type可以定义基本类型别名、联合类型、交叉类型。
-
enum和字面量联合类型的区别?
👉enum是运行时存在的对象;联合类型只是编译期的类型,不会生成 JS 代码。 -
什么是类型断言?和类型转换有什么区别?
👉 类型断言只是在编译期告诉编译器“我确定类型”,不会真的转换值。
📌 二、进阶题(泛型 & 工具类型)
-
泛型是什么?为什么要用泛型?
👉 泛型让类型像函数参数一样可复用,增强灵活性。 -
实现一个泛型工具类型
MyPick<T, K>。type MyPick<T, K extends keyof T> = { [P in K]: T[P]; }; -
Partial<T>、Required<T>、Readonly<T>、Record<K, T>的作用?
👉 都是 TypeScript 内置工具类型,用于对象属性的修饰。 -
如何定义一个只能接收字符串或数字的泛型函数?
function identity<T extends string | number>(arg: T): T { return arg; } -
解释
keyof、in、typeof在 TS 中的用法。
keyof→ 取对象的键组成联合类型。in→ 用在映射类型里遍历键。typeof→ 获取变量或函数的类型。
📌 三、类型体操(高频难点)
- 实现一个
Exclude<T, U>。
type MyExclude<T, U> = T extends U ? never : T;
- 实现一个
TupleToUnion<[string, number]>→"string" | "number"
type TupleToUnion<T extends any[]> = T[number];
- 实现一个
First<[1, 2, 3]>→1
type First<T extends any[]> = T extends [infer F, ...any[]] ? F : never;
- 解释一下
infer的作用?
👉infer用于条件类型中,推断出某个类型并命名。 - 写一个
DeepReadonly<T>工具类型。
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};
📌 四、工程实践题
- 在 React 项目里,如何给
props添加类型?
interface Props {
title: string;
onClick?: () => void;
}
const Button: React.FC<Props> = ({ title, onClick }) => <button>{title}</button>;
- 如何给 Axios 请求封装加类型?
interface User { id: number; name: string }
async function fetchUser(): Promise<User> {
const { data } = await axios.get<User>("/api/user");
return data;
}
- 如何在项目中开启严格模式?
👉tsconfig.json里"strict": true。 - 你在项目里遇到过哪些类型报错?是怎么解决的?
👉 比如:类型“{}”上不存在属性“xxx”,用类型收窄或Partial修正。 - 在 Node.js 里如何用 TS 开发?
👉 用ts-node或esbuild/tsup编译,tsconfig.json配置moduleResolution: "node"。📌 TypeScript 面试问答清单
🔹 一、基础部分
Q1: TypeScript 和 JavaScript 有什么区别?
👉 A: TypeScript 是 JavaScript 的超集,支持静态类型检查。JS 在运行时报错,TS 在编译期就能发现错误。TS 还增加了接口、枚举、泛型、装饰器等功能。
Q2: any 和 unknown 的区别是什么?
👉 A:
any可以绕过所有类型检查,赋值给任何类型。unknown更安全,必须先做类型缩小(例如typeof、类型断言)才能使用。
let a: any = 1; a.toFixed(); // OK
let b: unknown = 1; b.toFixed(); // ❌ 编译报错
Q3: interface 和 type 有什么区别?
👉 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: 解释一下 keyof、in、typeof 在 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"。
⚡ 总结:面试官通常会从 基础语法 → 泛型 & 工具类型 → 类型体操 → 工程实践 这四个层次提问。