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 #类型别名 #字面量类型 #联合类型 #交叉类型 #前端开发

相关推荐
weixin_382395235 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__5 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.6 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~7 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华8 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子10 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅10 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni10 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学12 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端