接口与类型别名
Interface 和 Type 是 TypeScript 中定义类型的两种主要方式,理解它们的区别和使用场景至关重要。
接口(Interface)
接口用于定义对象的形状(Shape)。
基本语法
interface User {
name: string;
age: number;
email: string;
}
const user: User = {
name: "Alice",
age: 25,
email: "alice@example.com"
};可选属性
interface Config {
url: string;
timeout?: number; // 可选
retry?: boolean; // 可选
}
const config: Config = {
url: "https://api.example.com"
// timeout 和 retry 可以省略
};只读属性
interface Point {
readonly x: number;
readonly y: number;
}
const point: Point = { x: 10, y: 20 };
// point.x = 30; // 错误:只读属性不能修改索引签名
// 字符串索引
interface StringMap {
[key: string]: string;
}
const colors: StringMap = {
red: "#ff0000",
green: "#00ff00"
};
// 数字索引
interface NumberArray {
[index: number]: string;
}
const arr: NumberArray = ["a", "b", "c"];函数类型接口
interface SearchFunc {
(source: string, keyword: string): boolean;
}
const search: SearchFunc = (source, keyword) => {
return source.includes(keyword);
};接口继承
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
// 多继承
interface Pet extends Animal, Dog {
owner: string;
}
const myDog: Dog = {
name: "Buddy",
breed: "Golden Retriever"
};接口合并(声明合并)
同名接口会自动合并:
interface User {
name: string;
}
interface User {
age: number;
}
// 合并后的 User
const user: User = {
name: "Alice",
age: 25
};类型别名(Type Alias)
Type 可以定义任何类型,不仅仅是对象。
基本语法
type ID = string | number;
type Name = string;
// 对象类型
type User = {
name: string;
age: number;
};
const user: User = {
name: "Alice",
age: 25
};联合类型
type Status = "pending" | "active" | "completed";
type ID = string | number;
let status: Status = "active";
let id: ID = 123;
id = "abc";交叉类型
type Name = {
name: string;
};
type Age = {
age: number;
};
type Person = Name & Age;
const person: Person = {
name: "Alice",
age: 25
};元组类型
type Point = [number, number];
type RGB = [number, number, number];
const point: Point = [10, 20];
const color: RGB = [255, 128, 0];函数类型
type Callback = (data: string) => void;
type AsyncCallback = (data: string) => Promise<void>;
const log: Callback = (data) => {
console.log(data);
};条件类型
type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // false映射类型
type Readonly<T> = {
readonly [K in keyof T]: T[K];
};
type Optional<T> = {
[K in keyof T]?: T[K];
};Interface vs Type 对比
| 特性 | Interface | Type |
|---|---|---|
| 对象类型 | ✅ | ✅ |
| 联合类型 | ❌ | ✅ |
| 交叉类型 | ❌(用 extends) | ✅ |
| 元组类型 | ❌ | ✅ |
| 原始类型别名 | ❌ | ✅ |
| 声明合并 | ✅ | ❌ |
| 继承/扩展 | extends | & |
| 实现(implements) | ✅ | ✅ |
何时使用 Interface
// 1. 定义对象形状
interface User {
name: string;
age: number;
}
// 2. 需要声明合并(如扩展第三方库类型)
declare global {
interface Window {
myCustomProperty: string;
}
}
// 3. 类实现
interface Printable {
print(): void;
}
class Document implements Printable {
print() {
console.log("Printing...");
}
}何时使用 Type
// 1. 联合类型
type Status = "pending" | "active" | "completed";
// 2. 元组
type Coordinates = [number, number];
// 3. 复杂类型组合
type Result<T> = { success: true; data: T } | { success: false; error: string };
// 4. 工具类型
type Nullable<T> = T | null;
type Keys<T> = keyof T;高级用法
递归类型
// 树形结构
type TreeNode = {
value: string;
children?: TreeNode[];
};
// JSON 类型
type JSONValue =
| string
| number
| boolean
| null
| JSONValue[]
| { [key: string]: JSONValue };模板字面量类型
type EventName = "click" | "focus" | "blur";
type EventHandler = `on${Capitalize<EventName>}`;
// "onClick" | "onFocus" | "onBlur"
type HTTPMethod = "GET" | "POST";
type APIPath = "/users" | "/posts";
type Endpoint = `${HTTPMethod} ${APIPath}`;
// "GET /users" | "GET /posts" | "POST /users" | "POST /posts"接口与类型的互操作
interface User {
name: string;
}
// Type 可以使用 Interface
type UserWithAge = User & { age: number };
// Interface 可以 extends Type
type HasEmail = { email: string };
interface Contact extends HasEmail {
phone: string;
}最佳实践
- 公共 API 使用 Interface:便于扩展和声明合并
- 内部类型使用 Type:更灵活,支持联合类型
- 保持一致性:团队内统一风格
- 优先组合而非继承:使用交叉类型组合功能
- 命名规范:接口不加
I前缀,类型不加T前缀
// 推荐
interface User {}
type UserID = string;
// 不推荐
interface IUser {}
type TUserID = string;