0

0

掌握 TypeScript 的模式匹配:增强代码的功能和安全性

DDD

DDD

发布时间:2024-12-03 22:42:01

|

516人浏览过

|

来源于dev.to

转载

掌握 typescript 的模式匹配:增强代码的功能和安全性

typescript 的可区分联合是一个强大的功能,它将模式匹配提升到一个新的水平。它们使我们能够创建复杂的、类型安全的条件逻辑,而不仅仅是简单的 switch 语句。我在最近的项目中广泛使用了这种技术,它改变了我在 typescript 中处理控制流的方式。

让我们从基础开始。可区分联合是一种使用公共属性来区分不同变体的类型。这是一个简单的例子:

type shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'rectangle'; width: number; height: number }

这里的“种类”属性是我们的判别式。它允许 typescript 根据其值推断我们正在处理的特定形状。

现在,让我们看看如何使用它进行模式匹配:

function getarea(shape: shape): number {
  switch (shape.kind) {
    case 'circle':
      return math.pi * shape.radius ** 2
    case 'rectangle':
      return shape.width * shape.height
  }
}

这很简洁,但这只是开始。我们可以更进一步。

受歧视工会最强大的方面之一是详尽检查。 typescript 可以确保我们在模式匹配中处理了所有可能的情况。让我们向我们的联合添加一个新形状:

type shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'rectangle'; width: number; height: number }
  | { kind: 'triangle'; base: number; height: number }

function getarea(shape: shape): number {
  switch (shape.kind) {
    case 'circle':
      return math.pi * shape.radius ** 2
    case 'rectangle':
      return shape.width * shape.height
    // typescript will now warn us that we're not handling the 'triangle' case
  }
}

为了使其更加健壮,我们可以添加一个引发错误的默认情况,确保我们永远不会意外忘记处理新情况:

function assertnever(x: never): never {
  throw new error("unexpected object: " + x);
}

function getarea(shape: shape): number {
  switch (shape.kind) {
    case 'circle':
      return math.pi * shape.radius ** 2
    case 'rectangle':
      return shape.width * shape.height
    case 'triangle':
      return 0.5 * shape.base * shape.height
    default:
      return assertnever(shape)
  }
}

现在,如果我们添加新形状而不更新 getarea 函数,typescript 会给我们一个编译时错误。

但是我们可以通过模式匹配走得更远。让我们看一个涉及嵌套模式的更复杂的示例。

想象一下我们正在为交通灯构建一个简单的状态机:

type trafficlightstate =
  | { state: 'green' }
  | { state: 'yellow' }
  | { state: 'red' }
  | { state: 'flashing', color: 'yellow' | 'red' }

function getnextstate(current: trafficlightstate): trafficlightstate {
  switch (current.state) {
    case 'green':
      return { state: 'yellow' }
    case 'yellow':
      return { state: 'red' }
    case 'red':
      return { state: 'green' }
    case 'flashing':
      return current.color === 'yellow'
        ? { state: 'red' }
        : { state: 'flashing', color: 'yellow' }
  }
}

在这里,我们不仅匹配顶级状态,而且当我们处于“闪烁”状态时也匹配嵌套属性。

我们还可以使用守卫为我们的模式匹配添加更复杂的条件:

type weatherevent =
  | { kind: 'temperature', celsius: number }
  | { kind: 'wind', speed: number }
  | { kind: 'precipitation', amount: number }

function describeweather(event: weatherevent): string {
  switch (event.kind) {
    case 'temperature':
      if (event.celsius > 30) return "it's hot!"
      if (event.celsius < 0) return "it's freezing!"
      return "the temperature is moderate."
    case 'wind':
      if (event.speed > 100) return "there's a hurricane!"
      if (event.speed > 50) return "it's very windy."
      return "there's a gentle breeze."
    case 'precipitation':
      if (event.amount > 100) return "it's pouring!"
      if (event.amount > 0) return "it's raining."
      return "it's dry."
  }
}

这种模式匹配方法不仅限于 switch 语句。我们可以将它与 if-else 链一起使用,甚至可以与对象文字一起使用以实现更复杂的场景:

type action =
  | { type: 'increment' }
  | { type: 'decrement' }
  | { type: 'reset' }
  | { type: 'set', payload: number }

const reducer = (state: number, action: action): number => ({
  increment: () => state + 1,
  decrement: () => state - 1,
  reset: () => 0,
  set: () => action.payload,
}[action.type]())

这种方法在实现访问者模式时特别有用。这是我们如何使用可区分联合来实现简单表达式求值器的示例:

type expr =
  | { kind: 'number'; value: number }
  | { kind: 'add'; left: expr; right: expr }
  | { kind: 'multiply'; left: expr; right: expr }

const evaluate = (expr: expr): number => {
  switch (expr.kind) {
    case 'number':
      return expr.value
    case 'add':
      return evaluate(expr.left) + evaluate(expr.right)
    case 'multiply':
      return evaluate(expr.left) * evaluate(expr.right)
  }
}

const expr: expr = {
  kind: 'add',
  left: { kind: 'number', value: 5 },
  right: {
    kind: 'multiply',
    left: { kind: 'number', value: 3 },
    right: { kind: 'number', value: 7 }
  }
}

console.log(evaluate(expr))  // outputs: 26

这种模式允许我们轻松地使用新类型的表达式来扩展我们的表达式系统,并且 typescript 将确保我们处理评估函数中的所有情况。

佳蓝在线销售系统(创业版) 佳蓝在线销售
佳蓝在线销售系统(创业版) 佳蓝在线销售

1、对ASP内核代码进行DLL封装,从而大大提高了用户的访问速度和安全性;2、采用后台生成HTML网页的格式,使程序访问速度得到进一步的提升;3、用户可发展下级会员并在下级购买商品时获得差额利润;4、全新模板选择功能;5、后台增加磁盘绑定功能;6、后台增加库存查询功能;7、后台增加财务统计功能;8、后台面值类型批量设定;9、后台财务曲线报表显示;10、完善订单功能;11、对所有传输的字符串进行安全

下载

这种方法最强大的方面之一是它如何允许我们将大型、复杂的条件块重构为更易于管理和扩展的结构。让我们看一个更复杂的例子:

想象一下我们正在构建一个系统来处理不同类型的金融交易:

type Transaction =
  | { kind: 'purchase', amount: number, item: string }
  | { kind: 'refund', amount: number, reason: string }
  | { kind: 'transfer', amount: number, to: string }
  | { kind: 'deposit', amount: number }
  | { kind: 'withdrawal', amount: number }

type TransactionProcessor = {
  [K in Transaction['kind']]: (transaction: Extract) => void
}

const processTransaction: TransactionProcessor = {
  purchase: ({ amount, item }) => {
    console.log(`Processing purchase of ${item} for $${amount}`)
    // Implement purchase logic
  },
  refund: ({ amount, reason }) => {
    console.log(`Processing refund of $${amount} for reason: ${reason}`)
    // Implement refund logic
  },
  transfer: ({ amount, to }) => {
    console.log(`Processing transfer of $${amount} to ${to}`)
    // Implement transfer logic
  },
  deposit: ({ amount }) => {
    console.log(`Processing deposit of $${amount}`)
    // Implement deposit logic
  },
  withdrawal: ({ amount }) => {
    console.log(`Processing withdrawal of $${amount}`)
    // Implement withdrawal logic
  }
}

function handleTransaction(transaction: Transaction) {
  processTransaction[transaction.kind](transaction as any)
}

在这个示例中,我们使用 typescript 的映射类型和条件类型来创建一个类型安全的对象,其中每个键对应一个事务类型,每个值都是处理该特定类型事务的函数。这种方法使我们能够轻松添加新类型的交易,而无需更改handletransaction函数的核心逻辑。

这种模式的美妙之处在于它既是类型安全的又是可扩展的。如果我们添加一种新的交易类型,typescript 会强制我们添加相应的处理器函数。如果我们尝试处理不存在的事务类型,我们将收到编译时错误。

这种具有可区分联合的模式匹配方法可以产生更具表现力、更安全和自记录的 typescript 代码,尤其是在复杂的应用程序中。它使我们能够以可读且可维护的方式处理复杂的逻辑。

随着我们的应用程序变得越来越复杂,这些技术变得越来越有价值。它们使我们能够编写不仅正确而且易于理解和修改的代码。通过充分利用 typescript 的类型系统,我们可以创建健壮、灵活的系统,并且使用起来很愉快。

请记住,我们的目标不仅仅是编写有效的代码,而是编写能够清楚表达其意图并且能够在需求变化时防止错误的代码。与可区分联合的模式匹配是实现此目标的强大工具。

根据我的经验,采用这些模式可以显着提高代码质量和开发速度。需要一些时间来习惯用可区分的联合和详尽的模式匹配来思考,但一旦你这样做了,你会发现它为以清晰、类型安全的方式构建代码开辟了新的可能性。

当您继续探索 typescript 时,我鼓励您寻找机会在自己的代码中应用这些模式。从小处开始,也许可以将复杂的 if-else 链重构为可区分联合。随着您对这项技术越来越熟悉,您将开始看到越来越多的地方可以应用它来简化和澄清您的代码。

请记住,typescript 的真正力量不仅在于它捕获错误的能力,还在于它能够引导我们获得更好、更具表现力的代码结构。通过采用可区分联合和详尽模式匹配等模式,我们可以创建不仅正确,而且易于阅读和维护的代码。


我们的创作

一定要看看我们的创作:

投资者中心 | 智能生活 | 时代与回响 | 令人费解的谜团 | 印度教 | 精英开发 | js学校


我们在媒体上

科技考拉洞察 | 时代与回响世界 | 投资者中央媒体 | 令人费解的谜团 | 科学与时代媒介 | 现代印度教

相关专题

更多
if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

751

2023.08.22

switch语句用法
switch语句用法

switch语句用法:1、Switch语句只能用于整数类型,枚举类型和String类型,不能用于浮点数类型和布尔类型;2、每个case语句后面必须跟着一个break语句,以防止执行其他case的代码块,没有break语句,将会继续执行下一个case的代码块;3、可以在一个case语句中匹配多个值,使用逗号分隔;4、Switch语句中的default代码块是可选的等等。

534

2023.09.21

Java switch的用法
Java switch的用法

Java中的switch语句用于根据不同的条件执行不同的代码块。想了解更多switch的相关内容,可以阅读本专题下面的文章。

415

2024.03.13

js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

510

2023.06.20

js获取当前时间
js获取当前时间

JS全称JavaScript,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言;它是一种属于网络的高级脚本语言,主要用于Web,常用来为网页添加各式各样的动态功能。js怎么获取当前时间呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

244

2023.07.28

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

258

2023.08.03

js是什么意思
js是什么意思

JS是JavaScript的缩写,它是一种广泛应用于网页开发的脚本语言。JavaScript是一种解释性的、基于对象和事件驱动的编程语言,通常用于为网页增加交互性和动态性。它可以在网页上实现复杂的功能和效果,如表单验证、页面元素操作、动画效果、数据交互等。

5283

2023.08.17

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

477

2023.09.01

PS使用蒙版相关教程
PS使用蒙版相关教程

本专题整合了ps使用蒙版相关教程,阅读专题下面的文章了解更多详细内容。

23

2026.01.19

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
TypeScript 教程
TypeScript 教程

共19课时 | 2.3万人学习

TypeScript——十天技能课堂
TypeScript——十天技能课堂

共21课时 | 1.1万人学习

TypeScript-45分钟入门
TypeScript-45分钟入门

共6课时 | 0.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号