TypeScript 的核心就是类型系统——它给 JavaScript 加了静态类型,让很多 bug 在编译期就暴露。平时写 Vue/React 天天用,但"interface 和 type 到底啥区别、联合/交叉类型、类型守卫"这些核心概念一直没系统梳理。这篇把 TS 类型系统最核心的几块讲清楚。
一、解决什么问题:JS 的弱类型之痛
JavaScript 是动态弱类型,变量类型运行时才确定,容易写出"数字 + 字符串 = 意外结果"这类 bug,而且 IDE 提示也弱。
TypeScript 加静态类型:变量声明时就确定类型,编译期就能查出类型错误:
typescript
// JS:类型自由,容易出错
let name = "BinMaker";
name = 18; // JS 允许,运行时可能出错
// TS:类型注解,编译期报错
let name: string = "BinMaker";
name = 18; // ❌ 编译报错:不能把 number 赋给 string好处:bug 从运行时提前到编译期,IDE 有完整的类型提示和补全。
二、基础类型与类型注解
typescript
let name: string = "BinMaker"; // 字符串
let age: number = 18; // 数字
let isVip: boolean = true; // 布尔
let tags: string[] = ["a", "b"]; // 字符串数组
let tuple: [string, number] = ["x", 1]; // 元组
let anything: any = "随便"; // any:放弃类型检查(尽量少用)
let nothing: null = null;any 是"逃生门"——用了它等于放弃类型检查,能不用就不用。
三、interface vs type(面试高频)
两者都能定义对象类型,但语义和用法有区别:
typescript
// interface:接口,可扩展、可声明合并
interface User {
name: string;
age: number;
}
interface Admin extends User { // 可 extends 扩展
role: string;
}
// type:类型别名,能表达更复杂的类型
type User = {
name: string;
age: number;
};
type ID = string | number; // type 能表示联合类型,interface 不能| 维度 | interface | type |
|---|---|---|
| 扩展 | extends 继承 | & 交叉 |
| 联合类型 | 不能 | 能(string | number) |
| 声明合并 | 能(同名 interface 自动合并) | 不能 |
| 适用 | 对象/类的结构(约定"形状") | 复杂类型(联合/交叉/映射) |
选型口诀:定义"对象的形状"优先 interface(可扩展),表达"复杂类型组合"(联合、交叉、映射)用 type。
四、联合类型与交叉类型
联合类型(|):是 A 或 B,二选一:
typescript
type ID = string | number; // 可以是 string 或 number
function printId(id: ID) {
console.log(id); // id 是 string | number
}交叉类型(&):是 A 且 B,合并:
typescript
type Named = { name: string };
type Aged = { age: number };
type Person = Named & Aged; // 同时有 name 和 age
const p: Person = { name: "BinMaker", age: 18 };一句话:| 是"或"(满足一个就行),& 是"且"(两个都要有)。
五、类型守卫:收窄类型
联合类型不能直接用特定类型的方法,要用类型守卫收窄:
typescript
// ① typeof:收窄基础类型(string/number/boolean...)
function getLen(x: string | number) {
if (typeof x === "string") {
return x.length; // 收窄为 string,能用 length
}
return x; // 收窄为 number
}
// ② instanceof:判断是否是某个类的实例
class Cat { meow() {} }
class Dog { bark() {} }
function makeSound(animal: Cat | Dog) {
if (animal instanceof Cat) {
return animal.meow(); // 收窄为 Cat,能调 meow
}
return animal.bark(); // 收窄为 Dog,能调 bark
}
// ③ in:判断对象是否有某个属性(判别联合类型)
type Circle = { kind: "circle"; radius: number };
type Square = { kind: "square"; side: number };
function getArea(shape: Circle | Square) {
if ("radius" in shape) {
return Math.PI * shape.radius ** 2; // 收窄为 Circle
}
return shape.side ** 2; // 收窄为 Square
}
// ④ is:自定义类型守卫(返回类型谓词 obj is User)
function isUser(obj: any): obj is User {
return obj && typeof obj.name === "string";
}
if (isUser(data)) {
data.name; // data 收窄为 User,能用 name
}四种类型守卫各管一类:typeof 收窄基础类型,instanceof 收窄类实例,in 判别对象形状(联合类型),is 自定义判断逻辑。
类型守卫(typeof、instanceof、in、is)让 TS 在判断分支里"知道"变量的具体类型,从而安全地调用方法。
小结
- TS 用静态类型把 bug 从运行时提前到编译期
interface定义对象形状(可扩展),type表达复杂类型(联合/交叉)- 联合
|= 或,交叉&= 且 - 类型守卫(typeof/instanceof/in/is)收窄联合类型,安全调用方法
any是逃生门,尽量少用
类型系统里还有个最核心、也最考验功力的概念——泛型,接着看《TypeScript 泛型》。
