Skip to content

字面量类型与类型别名

字面量类型让你可以指定变量必须是特定的值,而不仅仅是某种类型。类型别名则让你可以给类型起一个有意义的名字,提高代码可读性。这两个特性是 TypeScript 类型系统的重要组成部分。

字面量类型#

字符串字面量#

// TypeScript 5.x
// 字符串字面量类型
let direction: 'up' | 'down' | 'left' | 'right'
direction = 'up' // ✅
direction = 'down' // ✅
// direction = 'forward'; // ❌ 不在允许的值中
// 函数参数使用字面量类型
function move(dir: 'up' | 'down' | 'left' | 'right') {
console.log(`Moving ${dir}`)
}
move('up') // ✅
// move('diagonal'); // ❌ 错误

数字字面量#

// 数字字面量类型
type DiceValue = 1 | 2 | 3 | 4 | 5 | 6
function rollDice(): DiceValue {
return Math.floor(Math.random() * 6 + 1) as DiceValue
}
const result = rollDice() // 1 | 2 | 3 | 4 | 5 | 6
// HTTP 状态码
type SuccessCode = 200 | 201 | 204
type ClientErrorCode = 400 | 401 | 403 | 404
type ServerErrorCode = 500 | 502 | 503
type StatusCode = SuccessCode | ClientErrorCode | ServerErrorCode

布尔字面量#

// 布尔字面量
type True = true
type False = false
// 实际应用:条件类型的开关
type IsEnabled = true
function doSomething<T extends boolean>(
enabled: T
): T extends true ? string : number {
return (enabled ? 'enabled' : 0) as any
}
const a = doSomething(true) // string
const b = doSomething(false) // number

const 推断#

使用 const 声明时自动推断为字面量类型:

// let 推断为宽泛类型
let x = 'hello' // string
let y = 42 // number
// const 推断为字面量类型
const a = 'hello' // "hello"
const b = 42 // 42
// 但对象和数组不同
const obj = { name: 'hello' } // { name: string }
const arr = [1, 2, 3] // number[]
// 使用 as const 获得字面量类型
const objConst = { name: 'hello' } as const // { readonly name: "hello" }
const arrConst = [1, 2, 3] as const // readonly [1, 2, 3]

类型别名#

基本语法#

使用 type 关键字定义类型别名:

// 基础类型别名
type ID = string | number
type Name = string
// 对象类型别名
type User = {
id: ID
name: Name
email: string
}
// 函数类型别名
type Formatter = (value: number) => string
// 使用
const userId: ID = 123
const userName: Name = '张三'
const user: User = {
id: 1,
name: '张三',
email: 'zhangsan@example.com',
}
const format: Formatter = (n) => n.toFixed(2)

复杂类型别名#

// 联合类型别名
type Status = 'pending' | 'success' | 'error'
type Result<T> = { success: true; data: T } | { success: false; error: string }
// 交叉类型别名
type Timestamped = { createdAt: Date; updatedAt: Date }
type Identifiable = { id: string }
type Entity = Timestamped & Identifiable
// 条件类型别名
type NonNullable<T> = T extends null | undefined ? never : T
type Flatten<T> = T extends Array<infer U> ? U : T
// 递归类型别名
type JSONValue =
| string
| number
| boolean
| null
| JSONValue[]
| { [key: string]: JSONValue }

泛型类型别名#

// 泛型类型别名
type Container<T> = {
value: T
}
type Nullable<T> = T | null
type Optional<T> = T | undefined
type AsyncResult<T> = Promise<Result<T>>
// 使用
const numberContainer: Container<number> = { value: 42 }
const nullableString: Nullable<string> = null
const optionalNumber: Optional<number> = undefined

类型别名 vs 接口#

两者在很多场景下可以互换,但有一些关键区别:

语法差异#

// 对象类型:两者等价
type UserType = {
name: string
age: number
}
interface UserInterface {
name: string
age: number
}
// 函数类型
type FnType = (x: number) => number
interface FnInterface {
(x: number): number
}

接口可以合并#

// 接口可以多次声明,会自动合并
interface User {
name: string
}
interface User {
age: number
}
// 合并后:{ name: string; age: number }
const user: User = { name: '张三', age: 25 }
// 类型别名不能重复声明
// type User = { name: string };
// type User = { age: number }; // ❌ 错误:重复标识符

类型别名更灵活#

// 类型别名可以表示原始类型
type ID = string
type Name = string
// 类型别名可以表示联合类型
type Status = 'pending' | 'success' | 'error'
// 类型别名可以表示元组
type Point = [number, number]
// 类型别名可以使用 typeof
const config = { api: 'xxx', timeout: 5000 }
type Config = typeof config
// 接口只能表示对象类型
// interface Status = 'pending' | 'success' | 'error'; // ❌ 语法错误

继承方式不同#

// 接口使用 extends
interface Animal {
name: string
}
interface Dog extends Animal {
bark(): void
}
// 类型别名使用交叉类型
type AnimalType = {
name: string
}
type DogType = AnimalType & {
bark(): void
}
// 混合使用也可以
interface Cat extends AnimalType {
meow(): void
}
type Bird = Animal & {
fly(): void
}

何时用 type,何时用 interface?#

// ✅ 用 interface:定义对象结构、类的契约
interface UserService {
getUser(id: string): Promise<User>
updateUser(user: User): Promise<void>
}
class UserServiceImpl implements UserService {
async getUser(id: string) {
/* ... */
}
async updateUser(user: User) {
/* ... */
}
}
// ✅ 用 type:联合类型、元组、复杂类型操作
type Status = 'active' | 'inactive' | 'pending'
type Point = [number, number]
type Callback<T> = (error: Error | null, result: T) => void

🎯 实用建议:

从值创建类型#

typeof 操作符#

// 从值推断类型
const user = {
name: '张三',
age: 25,
roles: ['admin', 'user'],
}
type User = typeof user
// { name: string; age: number; roles: string[] }
// 从函数推断类型
function createUser(name: string, age: number) {
return { id: Math.random(), name, age }
}
type CreateUserFn = typeof createUser
// (name: string, age: number) => { id: number; name: string; age: number }
type UserFromFn = ReturnType<typeof createUser>
// { id: number; name: string; age: number }

keyof 操作符#

interface User {
id: number
name: string
email: string
}
type UserKeys = keyof User // "id" | "name" | "email"
// 结合索引访问
type UserValues = User[keyof User] // number | string
// 实用函数
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}
const user: User = { id: 1, name: '张三', email: 'test@test.com' }
const name = getProperty(user, 'name') // string
const id = getProperty(user, 'id') // number

从数组创建联合类型#

// 使用 as const 保留字面量类型
const METHODS = ['GET', 'POST', 'PUT', 'DELETE'] as const
type Method = (typeof METHODS)[number]
// "GET" | "POST" | "PUT" | "DELETE"
// 验证值
function request(method: Method, url: string) {
console.log(`${method} ${url}`)
}
request('GET', '/api/users') // ✅
// request('PATCH', '/api/users'); // ❌ 错误

从对象创建类型#

const STATUS = {
PENDING: 'pending',
SUCCESS: 'success',
ERROR: 'error',
} as const
// 键的联合
type StatusKey = keyof typeof STATUS // "PENDING" | "SUCCESS" | "ERROR"
// 值的联合
type StatusValue = (typeof STATUS)[keyof typeof STATUS]
// "pending" | "success" | "error"
// 使用
function handleStatus(status: StatusValue) {
switch (status) {
case STATUS.PENDING:
console.log('等待中...')
break
case STATUS.SUCCESS:
console.log('成功!')
break
case STATUS.ERROR:
console.log('失败!')
break
}
}

实际应用#

配置选项#

type LogLevel = 'debug' | 'info' | 'warn' | 'error'
type Environment = 'development' | 'staging' | 'production'
type Config = {
env: Environment
logLevel: LogLevel
apiUrl: string
features: {
darkMode: boolean
analytics: boolean
}
}
const config: Config = {
env: 'production',
logLevel: 'error',
apiUrl: 'https://api.example.com',
features: {
darkMode: true,
analytics: true,
},
}

事件系统#

type EventType = 'click' | 'hover' | 'scroll' | 'resize'
type EventHandler<T extends EventType> = T extends 'click'
? (x: number, y: number) => void
: T extends 'scroll'
? (scrollY: number) => void
: () => void
type EventMap = {
[K in EventType]: EventHandler<K>
}
const handlers: EventMap = {
click: (x, y) => console.log(`Clicked at ${x}, ${y}`),
hover: () => console.log('Hovered'),
scroll: (y) => console.log(`Scrolled to ${y}`),
resize: () => console.log('Resized'),
}

表单验证#

type FieldType = 'text' | 'email' | 'number' | 'date'
type FieldConfig<T extends FieldType> = {
type: T
required: boolean
label: string
placeholder?: string
} & (T extends 'number'
? { min?: number; max?: number }
: T extends 'text'
? { minLength?: number; maxLength?: number }
: {})
const emailField: FieldConfig<'email'> = {
type: 'email',
required: true,
label: '邮箱',
placeholder: 'example@email.com',
}
const ageField: FieldConfig<'number'> = {
type: 'number',
required: true,
label: '年龄',
min: 0,
max: 150,
}

常见问题#

🙋 字面量类型会增加代码量吗?#

合理使用会提高代码质量,而不是增加负担:

// ❌ 魔法字符串,容易出错
function setStatus(status: string) {
// ...
}
setStatus('sucess') // 拼写错误,不会报错
// ✅ 字面量类型,编译时检查
type Status = 'pending' | 'success' | 'error'
function setStatus2(status: Status) {
// ...
}
// setStatus2('sucess'); // ❌ 编译错误,立即发现问题

🙋 类型别名会影响运行时吗?#

不会。类型信息只存在于编译时:

type UserID = string
// 编译后的 JavaScript
// const id = "123"; // 类型信息完全消失
const id: UserID = '123'

🙋 循环引用类型怎么处理?#

TypeScript 支持类型的循环引用:

// 递归类型:树形结构
type TreeNode = {
value: string
children: TreeNode[]
}
// 链表
type LinkedNode<T> = {
value: T
next: LinkedNode<T> | null
}
// JSON 值
type JSONValue =
| string
| number
| boolean
| null
| JSONValue[]
| { [key: string]: JSONValue }

总结#

特性语法用途
字符串字面量'value'限定具体的字符串值
数字字面量42限定具体的数字值
类型别名type Name = ...给类型起名字
typeoftypeof value从值获取类型
keyofkeyof Type获取类型的键
as constvalue as const转为字面量类型

下一篇我们将进入接口的学习,深入了解 TypeScript 中定义对象结构的另一种重要方式。