精进TypeScript--【类型设计】倾向选择总是代表有效状态的类型

本文主要是介绍精进TypeScript--【类型设计】倾向选择总是代表有效状态的类型,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

如果你看不到代码所操作的数据或数据类型,代码就很难理解。这就是类型系统的一大优势:通过写出类型,让你的代码的读者可以看到它们,而且这也将使得你的代码变得易懂。

要记住的事情:

  • 既代表有效状态又代表无效状态的类型,很可能使得代码混乱,容易出错
  • 优先选择只代表有效状态的类型。即使它们较长或较难表达,但最终会为你节省时间和较少痛苦

假设你正在构建一个Web应用程序,允许你选择一个页面,加载该页面的内容,然后显示它:

interface State {pageText: string;isLoading: boolean;error?: string;
}

当你编写代码来渲染页面时,你需要考虑所有这些领域:

function renderPage(state: State) {if (state.error) {return `Error! Unable to load ${currentPage}: ${state.error}`;} else if (state.isLoading) {return `Loading ${currentPage}...`;}return `<h1>${currentPage}</h1>\n${state.pageText}`;
}

上面的做法对吗?如果 isLoading 和 error 都设置了呢?是显示加载信息好还是错误信息好?这个很难说,目前信息量不够。

或者,如果你要写一个changePage函数呢?比如:

async function changePage(state: State, newPage: string) {state.isLoading = true;try {const response = await fetch(getUrlForPage(newPage));if (!response.ok) {throw new Error(`Error! Unable to load ${newPage}: ${response.statusText}`);}const text = await response.text();state.isLoading = false;state.pageText = text;} catch(e) {state.error = '' + e;}
}

这里有很多问题:

  • 在错误的情况下,我们忘记将 state.isLoading 设置为 false
  • 我们没有清除 state.error,所以如果之前的请求失败,那么你会一直看到这个错误信息,而不是加载信息
  • 如果用户在页面加载过程中再次刷新页面,谁也不知道会发生什么。他们可能会看到一个新的页面,然后出现一个错误:或者看到第一个页面,而不是第二个页面,这取决于响应回来的顺序

问题在于状态包括的信息太少:哪个请求失败了?哪个正在加载?或者包括的信息太多:State 类型允许设置 isLoading 和 error,即使这代表一个无效的状态。这使得 render() 和 changePage() 都无法很好地实现。

这里有一种更好的方式来表示应用状态:

interface RequestPending {state: 'pending';
}
interface RequestError {state: 'error';error: string;
}
interface RequestSuccess {state: 'ok';error: string;
}
type RequestState = RequestPending | RequestError | RequestSuccess;interface State {currentPage: string;requests: {[page: string]: RequestState};
}

这里使用一个标签联合类型来明确地模拟网络请求可能处于的不同状态。尽管这个版本的状态要更长,但它有一个巨大的优势,就是不接受无效 状态。当前页面是基于显式建模的,你发出的每个请求的状态也是基于显式建模的。因此,renderPage 和 changePage 函数很容易实现:

function renderPage(state: State) {const {currentPage} = state;const requestState = state.requests[currentPage];switch (requestState.state) {case 'pending':return `Loading ${currentPage}...`;case 'error':return `Error! Unable to load ${currentPage}: ${requestState.error}`;case 'ok':return `<h1>${currentPage}</h1>\n${requestState.pageText}`;case default:return '';}
}async function changePage(state: State, newPage: string) {state.requests[newPage] = {state: 'pending'};state.currentPage = newPage;try {const response = await fetch(getUrlForPage(newPage));if (!response.ok) {throw new Error(`Error! Unable to load ${newPage}: ${response.statusText}`);}const pageText = await response.text();state.requests[newPage] = {state: 'ok', pageText};} catch(e) {state.requests[newPage] = {state: 'error', error: '' + e};}
}

和第一次实现相比,歧义完全消失了。当前页面是什么很清楚,每一个请求正好对应一个状态。如果用户在请求发出后改变了页面,那也没有问题。旧的请求仍然会完成,但不会影响 UI。

这篇关于精进TypeScript--【类型设计】倾向选择总是代表有效状态的类型的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/883811

相关文章

Python如何计算两个不同类型列表的相似度

《Python如何计算两个不同类型列表的相似度》在编程中,经常需要比较两个列表的相似度,尤其是当这两个列表包含不同类型的元素时,下面小编就来讲讲如何使用Python计算两个不同类型列表的相似度吧... 目录摘要引言数字类型相似度欧几里得距离曼哈顿距离字符串类型相似度Levenshtein距离Jaccard相

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要

linux进程D状态的解决思路分享

《linux进程D状态的解决思路分享》在Linux系统中,进程在内核模式下等待I/O完成时会进入不间断睡眠状态(D状态),这种状态下,进程无法通过普通方式被杀死,本文通过实验模拟了这种状态,并分析了如... 目录1. 问题描述2. 问题分析3. 实验模拟3.1 使用losetup创建一个卷作为pv的磁盘3.

Java实现状态模式的示例代码

《Java实现状态模式的示例代码》状态模式是一种行为型设计模式,允许对象根据其内部状态改变行为,本文主要介绍了Java实现状态模式的示例代码,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来... 目录一、简介1、定义2、状态模式的结构二、Java实现案例1、电灯开关状态案例2、番茄工作法状态案例

查询SQL Server数据库服务器IP地址的多种有效方法

《查询SQLServer数据库服务器IP地址的多种有效方法》作为数据库管理员或开发人员,了解如何查询SQLServer数据库服务器的IP地址是一项重要技能,本文将介绍几种简单而有效的方法,帮助你轻松... 目录使用T-SQL查询方法1:使用系统函数方法2:使用系统视图使用SQL Server Configu

通过prometheus监控Tomcat运行状态的操作流程

《通过prometheus监控Tomcat运行状态的操作流程》文章介绍了如何安装和配置Tomcat,并使用Prometheus和TomcatExporter来监控Tomcat的运行状态,文章详细讲解了... 目录Tomcat安装配置以及prometheus监控Tomcat一. 安装并配置tomcat1、安装

Linux之进程状态&&进程优先级详解

《Linux之进程状态&&进程优先级详解》文章介绍了操作系统中进程的状态,包括运行状态、阻塞状态和挂起状态,并详细解释了Linux下进程的具体状态及其管理,此外,文章还讨论了进程的优先级、查看和修改进... 目录一、操作系统的进程状态1.1运行状态1.2阻塞状态1.3挂起二、linux下具体的状态三、进程的

Redis的Zset类型及相关命令详细讲解

《Redis的Zset类型及相关命令详细讲解》:本文主要介绍Redis的Zset类型及相关命令的相关资料,有序集合Zset是一种Redis数据结构,它类似于集合Set,但每个元素都有一个关联的分数... 目录Zset简介ZADDZCARDZCOUNTZRANGEZREVRANGEZRANGEBYSCOREZ

IDEA如何将String类型转json格式

《IDEA如何将String类型转json格式》在Java中,字符串字面量中的转义字符会被自动转换,但通过网络获取的字符串可能不会自动转换,为了解决IDEA无法识别JSON字符串的问题,可以在本地对字... 目录问题描述问题原因解决方案总结问题描述最近做项目需要使用Ai生成json,可生成String类型

Python 中 requests 与 aiohttp 在实际项目中的选择策略详解

《Python中requests与aiohttp在实际项目中的选择策略详解》本文主要介绍了Python爬虫开发中常用的两个库requests和aiohttp的使用方法及其区别,通过实际项目案... 目录一、requests 库二、aiohttp 库三、requests 和 aiohttp 的比较四、requ