接口与类型别名
2026/7/9大约 4 分钟
接口与类型别名
概述
对于 Go 开发者来说,interface 是行为抽象的代名词 —— 定义一组方法签名,任何实现了这些方法的类型都隐式满足该接口。而 TypeScript 的 interface 则完全不同:它主要用于描述对象的结构(shape),而非行为。此外,TypeScript 提供了 type 关键字用于定义类型别名,这在 Go 中没有直接对应。
Go 开发者已知
// Go 接口 —— 行为抽象
type Writer interface {
Write([]byte) (int, error)
}
// 隐式实现
type File struct{}
func (f *File) Write(p []byte) (int, error) {
return len(p), nil
}
// 接口嵌入
type ReadWriter interface {
Reader
Writer
}
// 空接口
type Any interface{}Go 接口的核心特点:
- 接口定义方法集(行为契约)
- 实现是隐式的(duck typing)
- 接口嵌入实现方法的组合
- 没有属性/字段描述能力
TypeScript 怎么做
interface 定义对象形状
// 描述对象的结构(包含字段)
interface User {
id: number
name: string
email: string
age?: number // 可选属性
readonly createdAt: Date // 只读属性
}
// 使用
const user: User = {
id: 1,
name: 'Alice',
email: 'alice@example.com',
createdAt: new Date(),
}
// user.createdAt = new Date() // Error: 只读方法签名
// interface 也可以包含方法
interface HttpHandler {
(req: Request): Response // 调用签名
path: string // 属性
}
interface CRUD<T> {
create(item: T): void
read(id: string): T | null
update(id: string, item: T): void
delete(id: string): void
}type 别名
// 联合类型(interface 无法表达)
type Status = 'active' | 'inactive' | 'pending'
// 交叉类型
type Named = { name: string }
type Aged = { age: number }
type Person = Named & Aged // { name: string; age: number }
// 元组类型
type Pair = [string, number]
const pair: Pair = ['Alice', 30]
// 基本类型别名
type ID = string | number
type Callback = (err: Error | null, result?: unknown) => voidextends 继承
interface Base {
id: number
}
interface Admin extends Base {
role: 'admin'
permissions: string[]
}
// Admin 继承 id 字段
// 多个继承
interface Timestamp {
createdAt: Date
updatedAt: Date
}
interface SuperAdmin extends Admin, Timestamp {
level: number
}差异分析
| 维度 | Go | TypeScript |
|---|---|---|
| 接口本质 | 方法集,行为抽象 | 对象形状/结构描述 |
| 实现方式 | 隐式(duck typing) | 显式 implements |
| 组合机制 | 接口嵌入 | extends 继承 |
| 联合类型 | 不支持 | type A | B |
| 交叉类型 | 不支持 | type A & B |
| 元组 | 数组 | type Pair = [string, number] |
| 索引签名 | 不支持 | [key: string]: unknown |
Go 的 interface{} 对应什么?
Go 的 interface{} 在 TypeScript 中最精准的映射是 unknown(安全版本)或 any(逃逸版本)。
// Go: var x interface{}
let x: unknown
x = 42
x = "string"
x = { foo: 1 }但请注意:Go 的 interface{} 在运行时保留类型信息(通过反射),而 TypeScript 的类型在运行时被抹除,这是本质区别。
Bad Practice
// Bad: 同一概念混用 interface 和 type
interface User {
name: string
}
type User = { // Error: 重复声明
age: number
}
// Bad: 用 interface 表达联合类型(做不到)
// interface Status = 'a' | 'b' | 'c' // 语法错误
// Bad: 用 type 定义可扩展的公共 API
type Point = {
x: number
y: number
}
// type 不支持声明合并,消费者无法扩展
// Bad: 索引签名过度宽泛
interface Config {
[key: string]: string // 所有属性都必须是 string
port: number // Error: number 不兼容 string
}Best Practice
// Good: 公共 API 优先用 interface(支持声明合并)
interface User {
name: string
}
interface User {
age?: number // 声明合并:扩展 User
}
// Good: 联合/交叉类型用 type
type Status = 'active' | 'inactive'
type ApiResponse<T> =
| { status: 'success'; data: T }
| { status: 'error'; message: string }
// Good: 精确的索引签名
interface SafeConfig {
port: number
host: string
[key: string]: unknown // 允许额外属性,但需收窄
}
// Good: 使用 interface 定义 Props/State 契约
interface ButtonProps {
label: string
variant?: 'primary' | 'secondary'
disabled?: boolean
onClick: () => void
}
// Good: 使用 type 定义复杂工具类型
type DeepPartial<T> = {
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]
}声明合并(Declaration Merging)
interface 独有的声明合并特性非常强大:
// 在不同文件中逐步扩展同一个接口
// user.ts
interface User {
name: string
}
// user-extensions.ts
interface User {
age: number
}
// 最终 User 同时包含 name 和 age
const u: User = { name: 'Alice', age: 30 }type 不支持声明合并,这是选择 interface 还是 type 的关键区别。
code-tabs 对比
总结
| 场景 | 推荐构造 |
|---|---|
| 公共 API / 库类型 | interface |
| Props / State 定义 | interface |
| 需要声明合并 | interface |
| 联合 / 交叉类型 | type |
| 元组 | type |
| 工具类型 / 映射类型 | type |
| 基本类型别名 | type |
作为 Go 开发者,理解 TS interface = 结构描述(而非 Go 的行为抽象)是适应 TypeScript 的关键一步。下一章将介绍 函数签名与重载。