前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >通过五个真实应用场景,深入理解如何使用 TypeScript 枚举(enum)

通过五个真实应用场景,深入理解如何使用 TypeScript 枚举(enum)

作者头像
前端达人
发布2024-06-26 09:54:45
800
发布2024-06-26 09:54:45
举报
文章被收录于专栏:前端达人前端达人
如果你想让你的 TypeScript 代码更加有条理,枚举(enum)是一个非常强大的工具。它可以将相关的值组合在一起,使你的代码结构更加清晰,易于阅读。让我们深入了解一下如何使用它们吧!

一、简单的示例:方向操作

枚举的一个常见用例是:在有限的选项集合中进行选择,使代码更清晰明了。下面我们来看看一个简单的例子,通过枚举来处理方向操作。

代码语言:javascript
复制
enum Movement {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT"
}

function handlePlayerInput(key: string) {
  switch (key) {
    case Movement.Up:
      // 移动玩家角色向上
      console.log("移动玩家角色向上");
      break;
    case Movement.Down:
      // 移动玩家角色向下
      console.log("移动玩家角色向下");
      break;
    case Movement.Left:
      // 移动玩家角色向左
      console.log("移动玩家角色向左");
      break;
    case Movement.Right:
      // 移动玩家角色向右
      console.log("移动玩家角色向右");
      break;
    default:
      console.log("无效的输入");
  }
}

在这个例子中,我们定义了一个名为 Movement 的枚举,它包含四个成员,分别代表四个方向:上、下、左、右。然后,我们使用这个枚举在 handlePlayerInput 函数中处理玩家的输入。

为什么要用枚举?

  • 代码更清晰:使用枚举后,代码更具可读性。你可以清楚地看到每个方向对应的具体操作,而不必依赖字符串或数字。
  • 防止错误:枚举使得输入值更加有限,减少了拼写错误的可能性。例如,使用字符串时,容易出现拼写错误,而使用枚举则可以避免这种情况。
  • 易于维护:如果需要添加新的方向或修改现有的方向,只需在枚举中进行修改,而不需要在多个地方进行字符串替换。

总之,枚举让代码更加直观和可靠,是组织和管理固定选项集合的有效工具。

二、 HTTP 状态码

枚举不仅可以表示简单的选项集合,还可以关联特定的值(如数字、字符串等)。下面我们通过一个示例展示如何使用带值的枚举来确保类型安全,并防止使用任意数字。

代码语言:javascript
复制
enum StatusCode {
  OK = 200,
  BadRequest = 400,
  NotFound = 404
}

function handleResponse(code: StatusCode): string {
  if (code === StatusCode.OK) {
    return "请求成功";
  } else if (code === StatusCode.NotFound) {
    return "资源未找到";
  } else if (code === StatusCode.BadRequest) {
    return "错误请求";
  } else {
    return "未知响应码";
  }
}

// 假设我们有几个不同的响应码
const responseCode1 = 200;
const responseCode2 = 404;
const responseCode3 = 400;

// 将数字转换为StatusCode类型,并调用handleResponse函数
console.log(handleResponse(responseCode1 as StatusCode)); // 输出:请求成功
console.log(handleResponse(responseCode2 as StatusCode)); // 输出:资源未找到
console.log(handleResponse(responseCode3 as StatusCode)); // 输出:错误请求

在这个例子中,我们定义了一个名为 StatusCode 的枚举,它包含三个成员,分别代表 HTTP 状态码:200(OK),400(BadRequest),404(NotFound)。然后,我们在 handleResponse 函数中使用这个枚举来处理不同的 HTTP 响应码。

三、在 Redux Toolkit 中使用枚举

Redux Toolkit 是一个流行的状态管理库,特别适用于 React 应用。它大量使用 TypeScript 来确保类型安全。以下是一个定义异步操作状态的枚举,这在状态管理库中非常常见。

代码语言:javascript
复制
enum PayloadActionLoadingState {
  Idle = "idle",
  Loading = "loading",
  Failed = "failed",
  Success = "success"
}

这个枚举定义了异步操作的不同状态,如“空闲”(Idle)、“加载中”(Loading)、“失败”(Failed)和“成功”(Success)。在 Redux Toolkit 中,管理这些状态非常常见。

在 Redux Toolkit 中应用枚举

假设我们有一个 Redux slice 来管理异步数据获取操作的状态。我们可以使用 PayloadActionLoadingState 枚举来定义状态并处理相应的操作。

定义 Slice

首先,我们定义一个 Redux slice:

代码语言:javascript
复制
import { createSlice, PayloadAction } from '@reduxjs/toolkit';

interface DataState {
  data: any;
  loadingState: PayloadActionLoadingState;
  error: string | null;
}

const initialState: DataState = {
  data: null,
  loadingState: PayloadActionLoadingState.Idle,
  error: null,
};

const dataSlice = createSlice({
  name: 'data',
  initialState,
  reducers: {
    fetchDataStart(state) {
      state.loadingState = PayloadActionLoadingState.Loading;
      state.error = null;
    },
    fetchDataSuccess(state, action: PayloadAction<any>) {
      state.loadingState = PayloadActionLoadingState.Success;
      state.data = action.payload;
    },
    fetchDataFailed(state, action: PayloadAction<string>) {
      state.loadingState = PayloadActionLoadingState.Failed;
      state.error = action.payload;
    },
  },
});

export const { fetchDataStart, fetchDataSuccess, fetchDataFailed } = dataSlice.actions;

export default dataSlice.reducer;

使用 Slice 和 枚举

在 React 组件中使用这个 slice 和枚举:

代码语言:javascript
复制
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchDataStart, fetchDataSuccess, fetchDataFailed } from './dataSlice';
import { RootState } from './store';
import { PayloadActionLoadingState } from './payloadActionLoadingState';

const DataComponent: React.FC = () => {
  const dispatch = useDispatch();
  const { data, loadingState, error } = useSelector((state: RootState) => state.data);

  useEffect(() => {
    const fetchData = async () => {
      dispatch(fetchDataStart());
      try {
        const response = await fetch('https://api.example.com/data');
        const result = await response.json();
        dispatch(fetchDataSuccess(result));
      } catch (err) {
        dispatch(fetchDataFailed(err.toString()));
      }
    };

    fetchData();
  }, [dispatch]);

  if (loadingState === PayloadActionLoadingState.Loading) {
    return <div>Loading...</div>;
  }

  if (loadingState === PayloadActionLoadingState.Failed) {
    return <div>Error: {error}</div>;
  }

  if (loadingState === PayloadActionLoadingState.Success) {
    return <div>Data: {JSON.stringify(data)}</div>;
  }

  return <div>Idle</div>;
};

export default DataComponent;

解释

1、定义枚举

  • PayloadActionLoadingState 枚举定义了异步操作的四种状态。

2、创建 Slice

  • 定义了 DataState 接口来表示状态结构。
  • 使用 createSlice 创建了一个名为 data 的 slice,包含初始状态和 reducers。

3、处理异步操作

  • fetchDataStart:设置 loadingState 为 Loading,并清空错误信息。
  • fetchDataSuccess:设置 loadingState 为 Success,并存储获取到的数据。
  • fetchDataFailed:设置 loadingState 为 Failed,并存储错误信息。

4、在组件中使用

  • 使用 useDispatch 和 useSelector 访问 Redux 状态和 dispatch actions。
  • 在 useEffect 中发起异步请求,处理不同的状态。根据 loadingState 渲染不同的 UI。

通过使用枚举 PayloadActionLoadingState,我们确保了状态的类型安全,并使代码更具可读性和可维护性。希望这个例子能帮助你更好地理解如何在 Redux Toolkit 中使用枚举来管理异步操作状态。

四、使用枚举作为判别联合类型

这个例子展示了如何使用枚举来定义两个可能的形状:圆形(Circle)和矩形(Rectangle)。这是确保在处理不同形状时的类型安全的基础。

每个形状类型(Circle, Rectangle)都表示为 ShapeType 枚举的一个成员。

Shape 接口有一个 type 属性,它必须是 ShapeType 枚举的一个成员。

代码语言:javascript
复制
enum ShapeType {
    Circle = "Circle",
    Rectangle = "Rectangle"
}

interface Shape {
    type: ShapeType;
}

interface Circle extends Shape {
    type: ShapeType.Circle;
    radius: number;
}

interface Rectangle extends Shape {
    type: ShapeType.Rectangle;
    width: number;
    height: number;
}

function calculateArea(shape: Shape): number {
    switch (shape.type) {
        case ShapeType.Circle:
            const circle = shape as Circle; // 类型断言为 Circle
            return Math.PI * circle.radius * circle.radius;
        case ShapeType.Rectangle:
            const rectangle = shape as Rectangle; // 类型断言为 Rectangle
            return rectangle.width * rectangle.height;
        default:
            throw new Error("Invalid shape type");
    }
}

具体的形状接口(Circle, Rectangle)扩展了基础的 Shape 接口,并且必须将其 type 属性设置为对应的枚举值。

我们可以创建一些形状实例,并使用 calculateArea 函数来计算它们的面积:

代码语言:javascript
复制
const myCircle: Circle = {
    type: ShapeType.Circle,
    radius: 5
};

const myRectangle: Rectangle = {
    type: ShapeType.Rectangle,
    width: 10,
    height: 5
};

console.log(`Circle Area: ${calculateArea(myCircle)}`); // 输出:Circle Area: 78.53981633974483
console.log(`Rectangle Area: ${calculateArea(myRectangle)}`); // 输出:Rectangle Area: 50

代码解释

1、定义枚举

  • ShapeType 枚举包含两个成员:Circle 和 Rectangle,表示两种形状类型。

2、定义基础接口

  • Shape 接口有一个 type 属性,类型为 ShapeType 枚举。

3、扩展接口

  • Circle 接口扩展了 Shape,并添加了 radius 属性,同时将 type 属性固定为 ShapeType.Circle。
  • Rectangle 接口扩展了 Shape,并添加了 width 和 height 属性,同时将 type 属性固定为 ShapeType.Rectangle。

4、实现面积计算函数

  • calculateArea 函数接受一个 Shape 类型的参数,通过 switch 语句检查 type 属性,根据不同的形状类型执行相应的面积计算。
  • 使用类型断言(Type Assertion)将 Shape 类型的参数转换为具体的形状类型(Circle 或 Rectangle),从而访问特定属性。

通过这种方式,我们使用枚举来创建判别联合类型,使得 calculateArea 函数能够根据 type 属性进行分支处理,确保类型安全并执行正确的计算。

五、使用枚举作为数据结构

这个 TypeScript 示例展示了如何使用枚举来表示扑克牌的花色、等级以及根据花色派生的颜色属性。代码包括两个枚举、一个获取牌值的函数、一个描述牌结构的接口,以及一个创建牌的函数。

代码语言:javascript
复制
enum Suit {
  Hearts = "♥", // 红色花色
  Diamonds = "♦", // 红色花色
  Clubs = "♣", // 黑色花色
  Spades = "♠" // 黑色花色
}

enum Rank {
  Ace = 1,
  Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten,
  Jack, Queen, King 
}

function getCardValue(rank: Rank): number {
  if (rank <= Rank.Ten) {
    return rank;
  } else {
    return 10;
  }
}

interface Card {
  suit: Suit;
  rank: Rank;
  color: string; // 根据花色派生的属性
}

function createCard(suit: Suit, rank: Rank): Card {
  return {
    suit,
    rank,
    color: suit === Suit.Hearts || suit === Suit.Diamonds ? 'Red' : 'Black'
  }
}

// 使用示例
let card1 = createCard(Suit.Hearts, Rank.Ace);
console.log(`The Ace of Hearts is red: ${card1.color}`); // 输出:The Ace of Hearts is red: Red

let card2 = createCard(Suit.Spades, Rank.Queen);
console.log(`The Queen of Spades is black: ${card2.color}`); // 输出:The Queen of Spades is black: Black

解释

1、定义枚举

  • Suit 枚举定义了扑克牌的四种花色,每种花色都有一个符号表示。
  • Rank 枚举定义了扑克牌的等级,从 Ace 到 King。

2、获取牌值的函数

  • getCardValue 函数接受一个 Rank 类型的参数,并返回该牌的数值。对于 Ace 到 Ten,它们的数值等于等级本身。对于 Jack、Queen 和 King,它们的数值为 10。

3、定义牌的接口

  • Card 接口描述了一张牌的结构,包括花色、等级和颜色属性。颜色属性是根据花色派生的,红色花色(Hearts 和 Diamonds)为红色,黑色花色(Clubs 和 Spades)为黑色。

4、创建牌的函数

  • createCard 函数接受花色和等级作为参数,并返回一个 Card 对象。该函数根据花色来设置颜色属性。

这个示例展示了如何使用 TypeScript 的枚举和接口来创建一个简单的扑克牌模型。通过枚举,我们可以确保花色和等级的类型安全,通过接口,我们可以定义牌的结构,使代码更加清晰和易于维护。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端达人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、简单的示例:方向操作
    • 为什么要用枚举?
    • 二、 HTTP 状态码
    • 三、在 Redux Toolkit 中使用枚举
      • 在 Redux Toolkit 中应用枚举
        • 定义 Slice
        • 使用 Slice 和 枚举
    • 四、使用枚举作为判别联合类型
      • 代码解释
      • 五、使用枚举作为数据结构
        • 解释
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档