前端开发者应该知道的TypeScript可区分联合

图片

作为一个前端开发者,你的工作不仅仅是移动像素,前端的大部分复杂性来自于处理你的应用程序可能处于的所有不同状态。

它可能是加载数据,等待表单被填写,或者发送一个遥测事件 - 或者同时进行这三项。

如果不能正确处理状态,就可能陷入困境,而处理状态要从它们在类型中如何表示开始。

“可选包”

假设你正在构建一个简单的数据加载器,你可以选择使用如下类型来表示其状态:

 
interface State {  status: "loading" | "error" | "success";  error?: Error;  data?: { id: string };}// Some examples:const example: State = {    status: "loading"};const example2: State = {    status: "error",    error: new Error("Oh no!")};

这看起来很不错 - 我们可以检查  status  来理解我们应该在屏幕上显示哪种 UI。

除了 - 这种类型让我们声明所有应该不可能的形状:

 
const example3: State = {  status: "success",  // Where's the data?!};

这里,我们处于成功状态 - 这应该让我们访问数据。但它不存在!

 
const example4: State = {  status: "loading",  // We're loading, but we still have an error?!  error: new Error("Eek!"),};

在这里,我们处于加载状态 - 但我们的数据对象仍然有一个错误!

这是因为我们选择使用我称之为“可选包”的状态来表示我们的状态——一个充满可选属性的对象。

可选属性最好用于值可能存在或可能不存在的情况,在本例中,这是不正确的。

  • 当 status 是 loading 时, data 或 error 永远不存在。

  • 当 status 是 success 时, data 总是存在。

  • 当 status 是 error 时, error 总是存在。


可区分联合
 

更准确地表示这种情况的方法是使用 discriminated union,即可区分联合。

让我们从将状态更改为对象的联合开始,每个对象都包含一个状态。

 
type State =  | {      status: "loading";    }  | {      status: "success";    }  | {      status: "error";    };

现在我们已经有了基本框架,可以开始向联合的每个分支添加元素了。让我们重新添加错误和数据类型。

 
type State =  | {      status: "loading";    }  | {      status: "success";      data: {        id: string;      };    }  | {      status: "error";      error: Error;    };

现在,上面的例子将开始出错。

 
// Error: Property 'data' is missingconst example3: State = {  status: "success",};const example4: State = {  status: "loading",  // Error: Object literal may only specify known  // properties, and 'error' does not exist  error: new Error("Eek!"),};

我们的  State  类型现在正确地表示了特性的所有可能状态,这是向前迈出的一大步,但我们还没有完成。


解构可区分联合
 

让我们假设我们位于代码库中的组件内部,我们已经接收到状态片段,并希望使用它来渲染一些 JSX。

我在这里使用 React,但这可以是任何前端框架。

许多开发人员的第一反应是解构  State  的元素,但您会立即遇到错误:

 
const Component = () => {  const [state, setState] = useState<State>({    status: "loading",  });  const {    status,    // Error: Property 'data' does not exist on type 'State'.    data,    // Error: Property 'error' does not exist on type 'State'.    error,  } = state;};

对于许多开发者来说,这将是棘手的问题,因为  data  和  error  都可以存在于  State  上,所以为什么我得到错误?

原因是我们还没有试图区分这个 union,我们不知道自己在哪个状态,所以唯一可用的属性是 union 中所有成员共享的属性,即  status 。

一旦我们检查了我们所在的联合分支,我们就可以安全地解构  state !

 
if (state.status === "success") {  const { data } = state;}

这种严格性是一个特性,而不是一个 bug,通过确保你只能在状态等于  success  时访问数据,鼓励你从状态的角度来考虑应用,并且只在可用的状态下访问数据。


总结
 

当你开始从区分状态的角度考虑你的应用时,很多事情就变得容易了。

你将开始理解数据和 UI 之间的联系,而不是一个可选的大数据包。

不仅如此,你还能以一种全新的方式思考属性。

如果你需要以两种略有不同的方式显示组件,可以使用 discriminated union:

 
type ModalProps =  | {      variant: "with-description-and-button";      buttonText: string;      description: string;      title: string;    }  | {      variant: "base";      title: string;    };

这里,只有当传入的变量是  with-description-and-button  时,才需要  buttonText  和  description 。

 

欢迎关注公众号:文本魔术,了解更多

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/367317.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【PostgreSQL内核学习(二十五) —— (DBMS存储空间管理)】

DBMS存储空间管理 概述块&#xff08;或页面&#xff09;PageHeaderData 结构体HeapTupleHeaderData 结构 表空间表空间的作用&#xff1a;表空间和数据库关系表空间执行案例 补充 —— 模式&#xff08;Schema&#xff09; 声明&#xff1a;本文的部分内容参考了他人的文章。在…

深度学习入门笔记(七)卷积神经网络CNN

我们先来总结一下人类识别物体的方法: 定位。这一步对于人眼来说是一个很自然的过程,因为当你去识别图标的时候,你就已经把你的目光放在了图标上。虽然这个行为不是很难,但是很重要。看线条。有没有文字,形状是方的圆的,还是长的短的等等。看细节。纹理、颜色、方向等。卷…

C++学习Day01之namespace命名空间

目录 一、程序及输出1.1 命名空间用途&#xff1a; 解决名称冲突1.2 命名空间内容1.3 命名空间必须要声明在全局作用域下1.4 命名空间可以嵌套命名空间1.5 命名空间开放&#xff0c;可以随时给命名空间添加新的成员1.6 命名空间可以是匿名的1.7 命名空间可以起别名 二、分析与总…

洛谷 P1980 [NOIP2013 普及组] 计数问题

题目背景 NOIP2013 普及组 T1 题目描述 试计算在区间 1 到 n 的所有整数中&#xff0c;数字 x&#xff08;0≤x≤9&#xff09;共出现了多少次&#xff1f;例如&#xff0c;在 1 到 11 中&#xff0c;即在 1,2,3,4,5,6,7,8,9,10,11 中&#xff0c;数字 1 出现了 4 次。 输入…

基于Java SSM框架实现校园快领服务系统项目【项目源码+论文说明】

基于java的SSM框架实现校园快领服务系统演示 摘要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于校园快领服务系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了…

Electron+Vue3+Vite的产品级模板项目

1. electron-vue3-template 基于Vue3 Electron TypeScript的客户端程序模板&#xff0c;使用Vite和Electron Forge构建和打包。 真正做到开箱即用&#xff0c;面向跨平台客户端设计&#xff0c;产品级的项目模板。 项目地址&#xff1a; https://github.com/winsoft666/el…

Golang `crypto/hmac` 实战指南:代码示例与最佳实践

Golang crypto/hmac 实战指南&#xff1a;代码示例与最佳实践 引言HMAC 的基础知识1. HMAC 的工作原理2. HMAC 的应用场景 Golang crypto/hmac 库概览1. 导入和基本用法2. HMAC 的生成和验证3. crypto/hmac 的特性 实战代码示例示例 1: 基本的 HMAC 生成示例 2: 验证消息完整性…

C++通用编程(2)

函数模板高级用法 1.分文件编写的优点2.普通函数的分文件编写3.函数模板的分文件编写4.细节提示5.函数模板应用高级decltype推导类型函数后置返回类型 6.总结 函数模板讲完后&#xff0c;C全部的函数类型我们就接触的差不多了。今天给做一些关于函数份文件编写的知识点补充。 1…

C语言问题汇总

指针 #include <stdio.h>int main(void){int a[4] {1,2,3,4};int *p &a1;int *p1 a1;printf("%#x,%#x",p[-1],*p1);} 以上代码中存在错误。 int *p &a1; 错误1&#xff1a;取a数组的地址&#xff0c;然后1&#xff0c;即指针跳过int [4]大小的字节…

调试以及发布npm组件

开发原因&#xff1a; 由于公司自己的封装到npm的组件有点问题&#xff0c;负责人由在忙其他&#xff0c;就由我去负责改改&#xff0c;中途出了不少问题&#xff0c;记录一下。 一、下载源码 第一步肯定是去git上把组件的源码下载下来&#xff0c;这一步没什么好说&#xf…

日志记录——单片机可执行文件合并

一&#xff1a;需求场景 现在有一片单片机&#xff0c;执行程序包括自定义boot和应用程序app, 在将打包好的固件给到生产是有以下问题&#xff0c;由于要通过jlink烧录boot&#xff0c;然后上电启动boot&#xff0c;通过boot烧录初始化程序&#xff0c;过程过于复杂&#xff0…

Oracle和Mysql数据库

数据库 Oracle 体系结构与基本概念体系结构基本概念表空间(users)和数据文件段、区、块Oracle数据库的基本元素 Oracle数据库启动和关闭Oracle数据库启动Oracle数据库关闭 Sqlplussqlplus 登录数据库管理系统使用sqlplus登录Oracle数据库远程登录解锁用户修改用户密码查看当前语…

嵌入式软件中常见的 8 种数据结构

数据结构是一种特殊的组织和存储数据的方式&#xff0c;可以使我们可以更高效地对存储的数据执行操作。数据结构在计算机科学和软件工程领域具有广泛而多样的用途。 几乎所有已开发的程序或软件系统都使用数据结构。此外&#xff0c;数据结构属于计算机科学和软件工程的基础。当…

SpringBoot:@Profile注解和Spring EL

&#x1f3e1;浩泽学编程&#xff1a;个人主页 &#x1f525; 推荐专栏&#xff1a;《深入浅出SpringBoot》《java对AI的调用开发》 《RabbitMQ》《Spring》《SpringMVC》 &#x1f6f8;学无止境&#xff0c;不骄不躁&#xff0c;知行合一 文章目录 前言一、Prof…

业务流程自动化平台在制造业应用案例,助力业务自动化、智能化

捷昌驱动成立于2000年&#xff0c;并于2018年9月在上海证券交易所上市&#xff0c;是一家专注于线性驱动产品研发、生产及销售的科技集团。 公司整合全球资源&#xff0c;为智慧办公、医疗康护、智能家居、工业自动化等关联产业提供驱动及智能控制解决方案&#xff0c;以科技驱…

Linux系统安全:安全技术 和 防火墙

一、安全技术 入侵检测系统&#xff08;Intrusion Detection Systems&#xff09;&#xff1a;特点是不阻断任何网络访问&#xff0c;量化、定位来自内外网络的威胁情况&#xff0c;主要以提供报警和事后监督为主&#xff0c;提供有针对性的指导措施和安全决策依据,类 似于监控…

Sentinel安装

1、下载 sentinel官方提供了UI控制台&#xff0c;方便我们对系统做限流设置。大家可以在GitHub下载。 2、运行 将jar包放到任意非中文目录&#xff0c;执行命令&#xff1a; java -jar sentinel-dashboard-1.8.1.jar 如果要修改Sentinel的默认端口、账户、密码&#xff0c;…

【unity小技巧】unity3d环境带雾的昼夜系统变化

最终效果 文章目录 最终效果眩光素材眩光配置全局灯光配置天空盒配置天空盒资产配置天空盒&#xff0c;开启雾 代码控制天空盒 环境 雾 灯光昼夜交替变化参考完结 眩光素材 链接&#xff1a;https://pan.baidu.com/s/1qlFSJSju6ZjwCylwkh14eA?pwdveww 提取码&#xff1a;veww…

面试150 二进制求和 位运算

Problem: 67. 二进制求和 文章目录 思路复杂度Code 思路 &#x1f468;‍&#x1f3eb; 参考 复杂度 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( n ) O(n) O(n) Code class Solution {public String addBinary(String a, String b){StringBuilder ans new Stri…

【知识点】Java多线程

文章目录 线程基础happen-before规则基础概念线程方法线程状态转换状态控制参考链接 线程应用线程安全常用锁独享锁 VS 共享锁自旋锁可重入锁 VS 非可重入锁锁的状态无锁偏向锁轻量级锁重量级锁综述 公平锁非公平锁同步锁乐观锁悲观锁对比 AQS基础说明原理概览常用方法应用场景…
最新文章