TypeScript
1 类型基础
type 和 interface 的区别?什么时候用哪个?
interface:只能描述对象结构,支持
type:可以描述任何类型(联合、交叉、原始类型别名、元组),用
extends 继承和声明合并(同名 interface 自动合并)。type:可以描述任何类型(联合、交叉、原始类型别名、元组),用
& 交叉实现"继承",不能声明合并。
选择建议:定义组件 Props 和 API 契约用 interface(可扩展);定义联合类型、工具类型用 type。团队统一即可。
// interface — 声明合并
interface User { name: string; }
interface User { age: number; }
// 等价于 { name: string; age: number; }
// type — 联合类型
type Status = 'loading' | 'success' | 'error';
type Result = User & { status: Status };
联合类型 vs 交叉类型?
联合类型
交叉类型
A | B:值是 A 或 B 的其中一个,只能访问共有属性。交叉类型
A & B:值同时满足 A 和 B,拥有所有属性。
类型断言 vs 类型守卫?
类型断言(as):告诉编译器"我知道它是什么类型",不做运行时检查,可能不安全。
类型守卫:通过运行时检查收窄类型,更安全。如 typeof、instanceof、in、自定义
类型守卫:通过运行时检查收窄类型,更安全。如 typeof、instanceof、in、自定义
is 谓词。
// 类型断言 — 不安全
const el = document.getElementById('app') as HTMLDivElement;
// 类型守卫 — 安全
function isString(x: unknown): x is string {
return typeof x === 'string';
}
if (isString(value)) {
value.toUpperCase(); // TS 知道这里是 string
}
2 泛型
泛型是什么?为什么需要?
泛型是类型的参数,让函数/接口/类在定义时不指定具体类型,使用时再传入。好处是复用代码 + 保持类型安全,避免用 any 丧失类型检查。
// 不用泛型 — 丧失类型信息
function identity(arg: any): any { return arg; }
// 用泛型 — 保持类型安全
function identity<T>(arg: T): T { return arg; }
identity<string>('hello'); // 返回类型自动推断为 string
identity(42); // T 推断为 number
泛型约束 extends?
<T extends SomeType> 限制泛型参数必须满足某种结构,既保留灵活性又确保类型安全。
// 约束 T 必须有 length 属性
function logLength<T extends { length: number }>(arg: T): T {
console.log(arg.length);
return arg;
}
logLength('hello'); // ✅ string 有 length
logLength([1, 2]); // ✅ array 有 length
logLength(42); // ❌ number 没有 length
3 工具类型
常用内置工具类型?
Partial<T>:所有属性变可选Required<T>:所有属性变必填Pick<T, K>:只保留指定属性Omit<T, K>:排除指定属性Record<K, V>:构造键值对类型ReturnType<T>:提取函数返回类型Parameters<T>:提取函数参数类型(元组)
interface User {
id: number;
name: string;
email: string;
}
type UserPreview = Pick<User, 'id' | 'name'>;
type UserUpdate = Partial<Omit<User, 'id'>>;
// { name?: string; email?: string; }
Partial 的实现原理?
type MyPartial<T> = {
[K in keyof T]?: T[K];
};
// keyof T — 获取 T 的所有键组成的联合类型
// [K in ...] — 映射类型,遍历每个键
// ? — 标记为可选
4 高级类型
条件类型?infer 关键字?
T extends U ? X : Y — 类型层面的三元表达式。infer — 在条件类型中提取/推断类型。
// 提取 Promise 的返回类型
type Unwrap<T> = T extends Promise<infer R> ? R : T;
type A = Unwrap<Promise<string>>; // string
type B = Unwrap<number>; // number
// ReturnType 的实现原理
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
模板字面量类型?
TS 4.1+ 支持在类型中使用模板字面量语法,可以动态生成字符串类型。
type EventName = 'click' | 'scroll' | 'focus';
type Handler = `on${Capitalize<EventName>}`;
// 'onClick' | 'onScroll' | 'onFocus'
5 类型收窄
TS 有哪些类型收窄方式?
typeof:收窄原始类型instanceof:收窄类实例in:检查属性是否存在可辨识联合:通过共有的字面量属性(如
type: 'success' | 'error')收窄自定义类型守卫:
function isX(v): v is X
// 可辨识联合 — 最实用的收窄方式
type Success = { type: 'success'; data: string };
type Error = { type: 'error'; message: string };
type Result = Success | Error;
function handle(result: Result) {
switch (result.type) {
case 'success': return result.data; // TS 知道是 Success
case 'error': return result.message; // TS 知道是 Error
}
}