TypeScript 核心概念与实战解析
TypeScript 作为 JavaScript 的超集,通过引入静态类型系统显著提升了代码的可维护性与健壮性。以下整理了面试中高频出现的 TypeScript 知识点,涵盖基础类型、高级特性及工程化实践。
1. TypeScript 是什么?与 JavaScript 的核心区别
TypeScript (TS) 是 JavaScript 的超集,在保留 JS 语法的基础上增加了静态类型系统。最终编译为纯 JS 运行,兼容所有 JS 环境。其核心价值在于提升代码可维护性并减少运行时错误。
与 JavaScript 的关键差异:
- 类型系统:TS 拥有静态类型(编译阶段检查),JS 则是动态类型(运行时确定)。
- 编译阶段:TS 需通过编译器(如
tsc)编译校验后才能运行;JS 可直接执行。 - 特性补充:TS 新增接口、泛型、枚举等原生类型特性;JS 无此能力。
- 开发体验:TS 支持 IDE 智能提示与自动补全,能提前预警类型错误。
2. 基本数据类型
TS 支持原始类型与特殊类型,实习中需重点关注显式标注与特殊类型的用途。
- 原始类型:
string:字符串,如let name: string = "张三"。number:数字(含整数、浮点数)。boolean:布尔值(true/false)。null/undefined:空值与未定义,开启strictNullChecks后需单独识别。symbol:唯一标识(ES6 特性)。bigint:大整数类型。
- 特殊类型:
any:任意类型,关闭类型检查,不推荐滥用。unknown:未知类型,比any安全,使用前需断言。void:无返回值类型,常用于函数。never:永不存在的类型,如抛出错误的函数或无限循环。
3. 接口(Interface)与类型别名(Type Alias)的区别
两者均可定义对象/函数类型,但适用场景不同。
- 相同点:均支持泛型,均可定义对象结构。
- 核心区别:
- 扩展方式:Interface 使用
extends;Type Alias 使用交叉类型&。 - 声明合并:Interface 支持同名合并;Type Alias 不支持,同名会报错。
- 适用范围:Interface 仅用于对象/函数;Type Alias 可定义基础类型、联合类型等。
- 扩展方式:Interface 使用
- 使用建议:优先用 Interface 定义组件 Props 或 API 数据结构(便于扩展);优先用 Type Alias 处理联合类型或复杂复用。
4. 泛型(Generic)的作用与实例
泛型允许在定义时不指定具体类型,使用时动态传入,类似函数的参数传递。
- 为什么需要:避免使用
any导致类型丢失,实现一套逻辑支持多种类型。 - 实例:通用数组工具函数。
function getFirstElement<T>(arr: T[]): T | undefined {
return arr[0];
}
const strArr: string[] = ["a", "b"];
const firstStr = getFirstElement(strArr); // TS 推断 T 为 string
5. 类型断言(Type Assertion)
当 TS 无法自动推断类型时,开发者手动指定实际类型。仅在编译阶段生效。
- 两种常用方式:
- 尖括号语法:
<Type>value。不支持 JSX 场景。 - as 语法:
value as Type。推荐,支持所有场景。
- 尖括号语法:
- 注意事项:不能断言完全无关的类型;避免滥用,优先依赖自动推断。
6. any、unknown、never、void 对比
| 类型 | 含义 | 关键特性 | 场景 |
|---|---|---|---|
any | 任意类型 | 关闭检查,可调用任意方法 | 临时兼容旧代码 |
unknown | 未知类型 | 安全的 any,需断言后使用 | 接收外部数据 |
void | 无返回值 | 仅函数可用 | 日志类函数 |
never | 永不存在 | 不能赋值给任何类型 | 抛出错误或死循环 |
7. 可选属性与只读属性
- 可选属性:属性名后加
?,表示可省略。访问时需判断是否存在。 - 只读属性:属性名前加
readonly,初始化后不可修改(浅只读)。
interface User {
readonly id: string;
name: string;
age?: number;
}
8. 联合类型与交叉类型
- 联合类型 (
|):变量可以是多个类型中的任意一个。常用于处理多类型参数。 - 交叉类型 (
&):合并多个类型的属性。常用于合并用户信息与权限信息。
type ID = string | number; // 联合类型
type Admin = User & Permission; // 交叉类型
9. 类型守卫(Type Guard)
在运行时检查变量类型,缩小范围以便 TS 推断具体类型。
- 常用方式:
typeof:判断基础类型。instanceof:判断引用类型。in:判断对象是否包含某属性。- 自定义守卫:返回
param is Type的函数。
10. TypeScript 集成到 Vue 项目
以 Vue3 + Vite 为例,推荐使用 <script setup lang="ts">。
- 配置要点:
tsconfig.json:开启strict: true,配置lib和types。vite.config.ts:使用 TS 编写配置。
- 组件示例:
<script setup lang="ts">
import { ref } from 'vue';
const props = defineProps<{ username: string; age?: number }>();
const count = ref(0);
</script>
11. 枚举(Enum)
用于定义命名常量集合,提高可读性并约束取值范围。
- 数字枚举:默认从 0 开始递增,支持反向映射。
- 字符串枚举:语义更清晰,无反向映射冗余。建议优先使用。
12. 声明文件(.d.ts)
描述 JS 模块类型的文件,解决 TS 无法识别 JS 库的问题。
- 场景:引入无类型声明的第三方库,或自定义 JS 工具函数。
- 写法:
declare module "xxx" { ... }。
13. 异步函数类型处理
异步函数返回值为 Promise<T>,T 为成功后的数据类型。
interface User { id: string; name: string; }
async function fetchUsers(): Promise<User[]> {
const res = await fetch('/api/users');
return res.json();
}
14. 索引签名(Index Signature)
定义动态属性的对象,约束键值对类型。
interface ScoreMap {
[key: string]: number;
}
15. 类的继承与多态
- 继承:子类使用
extends,构造函数需调用super()。 - 多态:子类重写父类方法,同一方法在不同子类有不同行为。
16. readonly 与 const 的区别
- 作用对象:
readonly用于类/接口属性;const用于变量。 - 限制:
readonly限制属性重新赋值;const限制变量引用不可变(对象内部仍可改)。
17. 条件类型(Conditional Types)
基于条件推断类型,类似三元运算符作用于类型层面。
type ElementOf<T> = T extends Array<infer U> ? U : T;
18. 函数类型定义
覆盖函数声明、表达式、可选参数、默认参数及剩余参数。
function greet(name: string, age?: number): string { ... }
const add: (a: number, b: number) => number = (a, b) => a + b;
19. 模块系统与 JS 的区别
- 类型导出:TS 支持
export type/import type,明确区分类型与值。 - 路径解析:支持
baseUrl和paths配置简化导入。 - 类型检查:导入时即检查类型存在性。
20. 常见错误处理:属性不存在
遇到 'X' 上不存在属性 'Y' 错误,通常原因及解法:
- 类型定义不全:补充接口属性。
- 推断错误:使用类型断言或显式标注。
- 联合类型未缩小:使用类型守卫。
21. 映射类型(Mapped Types)
批量创建新类型,常用内置类型包括 Partial, Required, Readonly, Pick, Omit。
type PartialUser = Partial<User>;
type UserName = Pick<User, 'name'>;
22. DOM 元素类型处理
TS 提供专属类型(如 HTMLInputElement),需断言才能调用专属属性。
const input = document.getElementById('username') as HTMLInputElement;
input.value = 'test';
23. 严格模式(strict: true)
开启后启用一系列严格规则,如 noImplicitAny, strictNullChecks 等,强制严谨编码。
24. 泛型约束(Generic Constraints)
限制泛型范围,确保变量具备特定属性。
function getLength<T extends { length: number }>(value: T): number {
return value.length;
}
25. 实习常见问题与解决
- API 类型不匹配:检查字段是否为可选(如
age?: number),并在渲染前做空值判断。 - 第三方库无类型:优先安装
@types包,若无则手动编写.d.ts声明文件。
26. 类型推断(Type Inference)
TS 根据初始化值自动推断类型,减少手动标注。
let username = "张三"; // 推断为 string
const user = { name: "张三", age: 22 }; // 推断为对象类型
27. 函数重载
允许同一函数定义多个签名,根据入参自动匹配。
function formatDate(date: Date): string;
function formatDate(date: Date, format: string): string;
function formatDate(date: Date, format?: string): string { ... }
28. 命名空间(Namespace)与模块
- Namespace:单文件内组织代码,易污染全局,现代项目较少用。
- Module:独立文件,支持
import/export,是现代标准。
29. 抽象类(Abstract Class)
不能实例化的基类,用于定义子类公共接口。抽象方法必须在子类中实现。
30. 循环依赖处理
- 提取公共类型:将共享类型移至独立模块。
- 延迟导入:使用动态
import()避免初始化冲突。
31. 字面量类型(Literal Types)
表示具体值的类型,比普通类型更精确,常用于限制取值范围。
type ButtonType = "primary" | "secondary";
32. infer 关键字
在条件类型中推断类型变量,常用于提取泛型中的部分信息(如返回值、数组元素)。
33. 全局变量类型定义
通过扩展 Window 接口或在 .d.ts 文件中声明,告知 TS 全局变量的类型。
declare global {
interface Window {
appConfig?: { apiUrl: string };
}
}

