TypeScript 类型别名、字面量类型、联合类型与交叉类型

本文献给:

已掌握 TypeScript 基础类型(string、number、boolean、数组、元组、枚举)及特殊类型(any、unknown、void、never、null、undefined)的开发者。本文将带你学习如何通过类型别名、字面量类型、联合类型和交叉类型来构建更灵活、更精准的类型表达。

你将学到:

  1. 类型别名 type 的定义与使用场景
  2. 字符串字面量、数字字面量类型的含义
  3. as const 如何解决字面量推断问题
  4. 联合类型 | 的组合方式与属性访问限制
  5. 交叉类型 & 的合并特性

目录

  • [一、类型别名(Type Aliases)](#一、类型别名(Type Aliases))
    • [1.1 基本语法](#1.1 基本语法)
    • [1.2 对象类型别名](#1.2 对象类型别名)
    • [1.3 联合类型别名](#1.3 联合类型别名)
    • [1.4 类型别名 vs 接口](#1.4 类型别名 vs 接口)
  • [二、字面量类型(Literal Types)](#二、字面量类型(Literal Types))
    • [2.1 字符串字面量类型](#2.1 字符串字面量类型)
    • [2.2 数字字面量类型](#2.2 数字字面量类型)
    • [2.3 布尔字面量类型](#2.3 布尔字面量类型)
    • [2.4 字面量推断问题](#2.4 字面量推断问题)
  • [三、联合类型(Union Types)](#三、联合类型(Union Types))
    • [3.1 基本用法](#3.1 基本用法)
    • [3.2 函数参数中的联合](#3.2 函数参数中的联合)
    • [3.3 属性访问限制](#3.3 属性访问限制)
    • [3.4 字面量联合的优势](#3.4 字面量联合的优势)
  • [四、交叉类型(Intersection Types)](#四、交叉类型(Intersection Types))
    • [4.1 基本用法](#4.1 基本用法)
    • [4.2 合并冲突](#4.2 合并冲突)
    • [4.3 对象扩展场景](#4.3 对象扩展场景)
    • [4.4 交叉类型与联合类型的区别](#4.4 交叉类型与联合类型的区别)
  • [五、as const 深入](#五、as const 深入)
    • [5.1 对象字面量的 as const](#5.1 对象字面量的 as const)
    • [5.2 数组的 as const](#5.2 数组的 as const)
    • [5.3 as const 与枚举对比](#5.3 as const 与枚举对比)
  • 六、常见场景与示例
    • [6.1 类型别名 + 字面量联合定义状态](#6.1 类型别名 + 字面量联合定义状态)
    • [6.2 联合类型与交叉类型的组合](#6.2 联合类型与交叉类型的组合)
    • [6.3 as const 构建常量对象](#6.3 as const 构建常量对象)
    • [6.4 交叉类型扩展已有类型](#6.4 交叉类型扩展已有类型)
  • 七、常见错误与注意事项
    • [7.1 联合类型直接访问不存在属性](#7.1 联合类型直接访问不存在属性)
    • [7.2 交叉类型过度使用导致难以理解](#7.2 交叉类型过度使用导致难以理解)
    • [7.3 as const 与 let 的配合](#7.3 as const 与 let 的配合)
  • 八、综合示例
  • 九、小结

一、类型别名(Type Aliases)

1.1 基本语法

类型别名用来为任意类型起一个新名字,使用 type 关键字定义。

typescript 复制代码
type UserID = string;
type Age = number;

let id: UserID = "abc123";
let age: Age = 25;

类型别名可以描述复杂类型,让代码更清晰。

1.2 对象类型别名

常用于定义对象的结构:

typescript 复制代码
type Point = {
    x: number;
    y: number;
};

function distance(p1: Point, p2: Point): number {
    return Math.hypot(p1.x - p2.x, p1.y - p2.y);
}

1.3 联合类型别名

类型别名也可以用来给联合类型命名:

typescript 复制代码
type Status = "pending" | "success" | "error";

let currentStatus: Status = "pending";

1.4 类型别名 vs 接口

特性 类型别名 type 接口 interface
定义对象
定义联合
定义元组
合并声明 ❌(不可重复定义同名) ✅(同名接口自动合并)
扩展方式 & 交叉类型 extends 关键字

两者各有侧重,通常对象形状优先用 interface,联合、元组等场景用 type

二、字面量类型(Literal Types)

2.1 字符串字面量类型

字符串字面量类型允许将字符串的具体值作为类型,类似于枚举但更轻量。

typescript 复制代码
let direction: "left" | "right" | "up" | "down";
direction = "left";   // OK
direction = "top";    // ❌ 类型 "top" 不能赋给 "left" | "right" | "up" | "down"

2.2 数字字面量类型

同理,数字的具体值也可以作为类型:

typescript 复制代码
let dice: 1 | 2 | 3 | 4 | 5 | 6;
dice = 3;   // OK
dice = 7;   // ❌

2.3 布尔字面量类型

虽然很少单独用,但 truefalse 本身就是字面量类型。

typescript 复制代码
let isTrue: true = true;
isTrue = false;  // ❌

2.4 字面量推断问题

当使用 const 声明时,TypeScript 会推断出最精确的字面量类型:

typescript 复制代码
const a = "hello";   // 类型为 "hello"
let b = "hello";     // 类型为 string

但如果用 letvar,类型会被拓宽为基本类型。有时我们希望保留字面量类型,可以使用 as const

typescript 复制代码
let c = "hello" as const;       // 类型为 "hello"
let d = ["x", "y"] as const;    // 类型为 readonly ["x", "y"]

as const 将整个对象或数组变为只读,并推断为最具体的字面量类型。

typescript 复制代码
const config = {
    theme: "dark",
    size: 100
} as const;

// config 的类型为:
// {
//     readonly theme: "dark";
//     readonly size: 100;
// }

三、联合类型(Union Types)

3.1 基本用法

联合类型使用 | 分隔,表示值可以是多种类型中的一种。

typescript 复制代码
let value: string | number;
value = "hello";  // OK
value = 42;       // OK
value = true;     // ❌ 不能赋 boolean

3.2 函数参数中的联合

常用于接受多种类型的参数:

typescript 复制代码
function format(input: string | number): string {
    return `Result: ${input}`;
}

3.3 属性访问限制

当使用联合类型时,只能访问所有类型共有的属性或方法。

typescript 复制代码
interface Dog {
    name: string;
    bark(): void;
}

interface Cat {
    name: string;
    meow(): void;
}

type Pet = Dog | Cat;

function greet(pet: Pet) {
    console.log(pet.name);  // OK,name 是共有属性
    pet.bark();             // ❌ 不是所有 Pet 都有 bark
}

要使用特定类型的特有属性,需要先通过类型守卫收窄类型。

3.4 字面量联合的优势

字面量联合类型常用于替代枚举,更轻量且无运行时开销。

typescript 复制代码
type Theme = "light" | "dark" | "auto";

let currentTheme: Theme = "light";

四、交叉类型(Intersection Types)

4.1 基本用法

交叉类型使用 & 操作符,将多个类型合并为一个,新类型将拥有所有类型的成员。

typescript 复制代码
type Name = {
    name: string;
};

type Age = {
    age: number;
};

type Person = Name & Age;

let p: Person = {
    name: "Alice",
    age: 25
};

4.2 合并冲突

当交叉的类型有同名但类型不同的属性时,该属性会变成 never,通常意味着设计上需要调整。

typescript 复制代码
type A = { id: number };
type B = { id: string };

type C = A & B;  // id 的类型为 number & string → never
// 无法构造满足 C 的对象

4.3 对象扩展场景

交叉类型常用于组合多个对象类型,类似接口的继承:

typescript 复制代码
type Base = { id: string };
type Extended = Base & { createdAt: Date };

4.4 交叉类型与联合类型的区别

  • 联合类型(|):表示"或",值是其中一种类型。
  • 交叉类型(&):表示"且",值必须同时满足所有类型。

五、as const 深入

5.1 对象字面量的 as const

as const 告诉 TypeScript 将对象中的属性推断为字面量类型,并将所有属性设为 readonly

typescript 复制代码
const routes = {
    home: "/",
    user: "/user",
    admin: "/admin"
} as const;

// routes 的类型为:
// {
//     readonly home: "/";
//     readonly user: "/user";
//     readonly admin: "/admin";
// }

5.2 数组的 as const

数组用 as const 后会变成只读元组,元素类型为字面量。

typescript 复制代码
const sizes = ["small", "medium", "large"] as const;
// 类型为 readonly ["small", "medium", "large"]

type Size = typeof sizes[number];  // "small" | "medium" | "large"

这种模式常用于从数组定义联合类型,避免重复书写。

5.3 as const 与枚举对比

as const 结合数组或对象可以模拟枚举的行为,且没有运行时对象开销:

typescript 复制代码
// 模拟枚举
const StatusEnum = {
    Pending: "pending",
    Success: "success",
    Error: "error"
} as const;

type Status = typeof StatusEnum[keyof typeof StatusEnum];  // "pending" | "success" | "error"

六、常见场景与示例

6.1 类型别名 + 字面量联合定义状态

typescript 复制代码
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";

function request(url: string, method: HttpMethod) {
    // ...
}

6.2 联合类型与交叉类型的组合

typescript 复制代码
type Success = { data: string; code: 200 };
type Error = { error: string; code: 400 | 500 };

type ApiResponse = Success | Error;

function handle(response: ApiResponse) {
    if (response.code === 200) {
        console.log(response.data);  // 收窄为 Success
    } else {
        console.log(response.error); // 收窄为 Error
    }
}

6.3 as const 构建常量对象

typescript 复制代码
const config = {
    apiUrl: "https://api.example.com",
    timeout: 5000,
    retries: 3
} as const;

// 可以获取字面量类型
type Config = typeof config;
// {
//     readonly apiUrl: "https://api.example.com";
//     readonly timeout: 5000;
//     readonly retries: 3;
// }

6.4 交叉类型扩展已有类型

typescript 复制代码
type Timestamped = {
    createdAt: Date;
    updatedAt: Date;
};

type User = {
    id: string;
    name: string;
};

type TimestampedUser = User & Timestamped;

const user: TimestampedUser = {
    id: "1",
    name: "Alice",
    createdAt: new Date(),
    updatedAt: new Date()
};

七、常见错误与注意事项

7.1 联合类型直接访问不存在属性

typescript 复制代码
type Shape = { kind: "circle"; radius: number } | { kind: "square"; side: number };

function area(shape: Shape) {
    return shape.radius;   // ❌ 属性 radius 不存在于所有 Shape
}

必须使用类型守卫(如 if (shape.kind === "circle"))收窄。

7.2 交叉类型过度使用导致难以理解

过多的交叉类型会让类型变得复杂,必要时可以拆分为多个小类型别名。

7.3 as const 与 let 的配合

as const 配合 let 时,变量类型是字面量,但仍然可以被重新赋值(只要类型匹配)。

typescript 复制代码
let direction = "left" as const;  // 类型为 "left"
direction = "right";              // ❌ 类型 "right" 不能赋给 "left"

如果需要可变但保留字面量约束,应使用类型注解联合类型。

八、综合示例

typescript 复制代码
// 定义角色权限的类型别名
type Role = "admin" | "editor" | "viewer";

// 定义用户基础信息
type UserBase = {
    id: string;
    name: string;
};

// 定义带角色的用户
type User = UserBase & {
    role: Role;
    permissions?: string[];
};

// 使用 as const 定义权限列表
const allPermissions = ["read", "write", "delete"] as const;
type Permission = typeof allPermissions[number];  // "read" | "write" | "delete"

// 角色权限映射
type RolePermissions = {
    [K in Role]: Permission[];
};

const rolePermissions: RolePermissions = {
    admin: ["read", "write", "delete"],
    editor: ["read", "write"],
    viewer: ["read"]
};

// 检查用户权限
function hasPermission(user: User, permission: Permission): boolean {
    if (user.role === "admin") return true;
    const allowed = rolePermissions[user.role];
    return allowed.includes(permission);
}

// 使用
const currentUser: User = {
    id: "u1",
    name: "Alice",
    role: "editor"
};

console.log(hasPermission(currentUser, "write"));  // true
console.log(hasPermission(currentUser, "delete")); // false

九、小结

概念 语法示例 说明
类型别名 type ID = string 为任意类型起名字
字符串字面量 `type Dir = "left" "right"`
数字字面量 `type Dice = 1 2
as const const obj = { a: 1 } as const 推断为字面量只读类型
联合类型 `type T = A B`
交叉类型 type T = A & B 值必须同时满足 A 和 B
属性访问限制 联合类型只能访问共有成员 需类型守卫收窄

觉得文章有帮助?别忘了:

👍 点赞 👍 -- 给我一点鼓励
⭐ 收藏 ⭐ -- 方便以后查看
🔔 关注 🔔 -- 获取更新通知


标签: #TypeScript #类型别名 #字面量类型 #联合类型 #交叉类型 #前端开发

相关推荐
JOEH602 小时前
为什么你的 CPU 总是突然飙高?Java 生产环境 6 大排查误区
javascript·后端
烛衔溟2 小时前
TypeScript 特殊类型与空值安全
安全·typescript·前端开发·空值处理
Cache技术分享2 小时前
369. Java IO API - DOS 文件属性
前端·后端
慧一居士2 小时前
Nuxt4 项目的约定配置都有哪些,哪些可以自动实现, 详细示例和使用说明
前端·vue.js
芯智工坊2 小时前
每周一个开源项目 #4:ChatGPT-Next-Web 增强版
前端·chatgpt·开源
左右用AI2 小时前
每周1亿次下载的axios被投毒了,但是源码里没有一行恶意代码!
前端·后端
英俊潇洒美少年2 小时前
前端模块化 AMD、CMD、CommonJS、ESM的差异对比
前端
攀登的牵牛花2 小时前
Claude Code 泄露事件复盘:前端发布流程哪里最容易翻车
前端·github·claude
D_C_tyu2 小时前
vue3 + vue3-print-nb 插件实现打印功能
前端·javascript·vue.js