字面量类型让你可以指定变量必须是特定的值,而不仅仅是某种类型。类型别名则让你可以给类型起一个有意义的名字,提高代码可读性。这两个特性是 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 | 204type ClientErrorCode = 400 | 401 | 403 | 404type ServerErrorCode = 500 | 502 | 503
type StatusCode = SuccessCode | ClientErrorCode | ServerErrorCode布尔字面量#
// 布尔字面量type True = truetype 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) // stringconst b = doSomething(false) // numberconst 推断#
使用 const 声明时自动推断为字面量类型:
// let 推断为宽泛类型let x = 'hello' // stringlet 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 | numbertype Name = string
// 对象类型别名type User = { id: ID name: Name email: string}
// 函数类型别名type Formatter = (value: number) => string
// 使用const userId: ID = 123const 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 : Ttype 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 | nulltype Optional<T> = T | undefined
type AsyncResult<T> = Promise<Result<T>>
// 使用const numberContainer: Container<number> = { value: 42 }const nullableString: Nullable<string> = nullconst 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 = stringtype Name = string
// 类型别名可以表示联合类型type Status = 'pending' | 'success' | 'error'
// 类型别名可以表示元组type Point = [number, number]
// 类型别名可以使用 typeofconst config = { api: 'xxx', timeout: 5000 }type Config = typeof config
// 接口只能表示对象类型// interface Status = 'pending' | 'success' | 'error'; // ❌ 语法错误继承方式不同#
// 接口使用 extendsinterface 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🎯 实用建议:
- 团队统一风格最重要
- 需要合并声明时用
interface - 需要联合类型、元组时用
type - 简单对象结构两者都可以
从值创建类型#
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') // stringconst 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 = ... | 给类型起名字 |
| typeof | typeof value | 从值获取类型 |
| keyof | keyof Type | 获取类型的键 |
| as const | value as const | 转为字面量类型 |
下一篇我们将进入接口的学习,深入了解 TypeScript 中定义对象结构的另一种重要方式。