写出更优雅和稳健的 TS 代码的几个 tips

news2024/11/20 13:17:18

写出更优雅和稳健的 TS 代码的几个 tips

本来想放优雅 太优雅了.jpg,后来还是好懒啊……

使用 unknown 代替 any

any 的问题在于它直接关闭了 TS 的类型检查,因此一旦使用了 any,那就代表任何事情都会发生。使用 unknown 则告诉 TS:在目前这个步骤我还不知道使用的数据类型,不过当我去使用该变量的时候,我就知道这个类型是什么了(多为类型检查)。

参考一下代码:

interface IUser {
  id: number;
  firstname: string;
  lastname: string;
  gender: string;
  image: string;
  age: number;
}

interface IAdminUser extends IUser {
  token: string;
  addNewUser: () => void;
}

const isAdmin = (object: unknown): boolean => {
  return true;
};

const fetchUser = async () => {
  const res = await fetch('http://localhost:3000/users/1');

  // bad ❌
  const badUser = await res.json();
  console.log(badUser.nonExistingProp);

  // good ✅
  const goodUser: unknown = await res.json();
  console.log(goodUser.nonExistingProp);

  // add type guard
  if (isAdmin(goodUser)) {
  }
};

在这里插入图片描述

直接使用 any 的代码不会出现任何的报错,而使用 unknown 则是会强制要求进行类型检查才能继续。

使用 is

is 也是一种类型断言,稍微修改一下上面的代码中对 user 的检查:

const isAdmin = (object: unknown): object is IAdminUser => {
  if (object !== null && typeof object === 'object') {
    return 'token' in object;
  }

  return false;
};

const isRegularUser = (object: unknown): object is IUser => {
  if (object !== null && typeof object === 'object') {
    return 'token'! in object;
  }

  return false;
};

在这里插入图片描述

在调用时,TS 就会遵从 object is IAdminUser,在返回值为 true 的时候断言返回类型为 IAdminUser,这时候 goodUser 中就会包含所有管理员权限应该有的属性和函数。

同理,如果检查下来用户不是管理员,那么该用户也就无法调用管理员才能使用的属性和函数:

在这里插入图片描述

另一种需要 is 的情况是 Union Type,Union Type 的定义也是 type 乱用的重灾区。

function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}

// Both calls to 'swim' and 'fly' are now okay.
let pet = getSmallPet();

if (isFish(pet)) {
  pet.swim();
} else {
  pet.fly();
}

const zoo: (Fish | Bird)[] = [getSmallPet(), getSmallPet(), getSmallPet()];
const underWater1: Fish[] = zoo.filter(isFish);
// or, equivalently
const underWater2: Fish[] = zoo.filter(isFish) as Fish[];

// The predicate may need repeating for more complex examples
const underWater3: Fish[] = zoo.filter((pet): pet is Fish => {
  if (pet.name === 'sharkey') return false;
  return isFish(pet);
});

可能对于单独一个对象而已,使用 as 进行 type casting 问题不是很大,不过对于之后要重新声明的数组等,一直使用 as 去转确实挺麻烦的。不过有了现在这个方法,就可以忽略掉 as Type[] 这种声明了。

使用 satisfies 关键词

satisfies 是 4.9 新出的一个特性,已下面代码为案例:

interface ICustomImage {
  width: number;
  height: number;
  data: string;
}

interface IUser {
  id: number;
  firstname: string;
  lastname: string;
  image: string | ICustomImage;
}

const user: IUser = {
  id: 1,
  firstname: '',
  lastname: '',
  image: 'random url',
};

在这里插入图片描述

可以看到,尽管声明的是一个字符串,不过因为 union type 的关系,TS 无法明确认识 user.image 究竟是字符串还是对象,但是使用 satisfies 关键词之后则是另一个情况:

在这里插入图片描述

在这里插入图片描述

TS 能够更好的通过数据类型进行断言和提示。

正确使用 enum

这里指的是尽量不要使用默认的 enum 类型(即数字),如:

在这里插入图片描述

尽管 100 不在 State 中(默认应该从 0 开始,所以这里只有 0,1,2),但是传参时检查失败。不过使用字符串就可以避免这个问题了:

在这里插入图片描述

在这里插入图片描述

善用 Utility Type

这里提一个我刚找到能够很好的解决我目前一个 CRUD 操作的组合技:

interface IUser {
  id: number;
  firstname: string;
  lastname: string;
  gender: string;
  image: string;
  age: number;
}

const updateUser = (
  userId: IUser['id'],
  updatedUser: Partial<Omit<IUser, 'id'>>
) => {};

在这里插入图片描述

这时候查看就能够发现,所有的选项已经变成了 optional,而 id 已经从可更新的状态中移除了。

Util Types真的还蛮有用的……不过我之前看的一些教程都没讲,晚点这块继续补一下吧。

参考

  • Using type predicates

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LIS源码 医院检验科LIS系统源码 .net检验系统源码 实验室信息管理系统源码全开源,价值百万

LIS系统即实验室信息管理系统。LIS系统能实现临床检验信息化&#xff0c;检验科信息管理自动化。其主要功能是将检验科的实验仪器传出的检验数据经数据分析后&#xff0c;自动生成打印报告&#xff0c;通过网络存储在数据库中&#xff0c;使医生能够通过医生工作站方便、及时地…

PXE+Kickstart 自动化部署系统

PXE 预启动执行环境是由Intel开发的技术,可以让计算机通过网络来启动操作系统(前提是计算机上安装的网卡支持PXE技术),主要用于在无人值守安装系统中引导客户端主机安装Linux操作系统. Kickstart是一种无人值守的安装方式,其工作原理是预先把原本需要运维人员手工填写的参数保…

谷粒商城之高级篇(2)

2.6 购物车服务 2.6.1 环境搭建 ①域名配置 ②创建 微服务 暂时需要的插件 此外&#xff0c;导入 公共包的依赖 <dependency><groupId>com.atguigu.gulimall</groupId><artifactId>gulimall-common</artifactId><version>0.0.1-SNAPSHOT…

50. 残差网络(ResNet)代码实现

1. 残差块 ResNet沿用了VGG完整的 33 卷积层设计。 残差块里首先有2个有相同输出通道数的 33 卷积层。 每个卷积层后接一个批量规范化层和ReLU激活函数。 然后我们通过跨层数据通路&#xff0c;跳过这2个卷积运算&#xff0c;将输入直接加在最后的ReLU激活函数前。 这样的设计…

PDF在线转Word?方便快捷易上手的方法

PDF和Word都是我们日常生活中经常看到的文件格式&#xff0c;如果你也是一个工作党&#xff0c;那小编相信你肯定会遇到关于这两种文件的转换问题。其实&#xff0c;PDF格式是十分方便我们进行文件传输和差阅读&#xff0c;不仅兼容性较强&#xff0c;而且文件内容相对来说是固…

罗克韦尔AB PLC安装Studio 5000 V35的具体步骤演示

罗克韦尔AB PLC安装Studio 5000 V35的具体步骤演示 具体安装步骤可参考如下内容: 解压下载的安装包,找到安装包中的Setup.exe, 如下图所示,右击Setup.exe,选择“以管理员身份运行”, 如下图所示,安装程序正在准备中, 如下图所示,此时安装程序报错:未安装Microsoft…

ARM64内存虚拟化分析(6)向KVM注册内存更新

1 KVM memory listener的注册 在KVM初始化kvm_init()中会通过函数km_memory_listener_regiter()注册KVM所对应的memory listener&#xff0c;其中设置KVM region_add回调&#xff0c;KVM region_del回调以及KVM log_start/log_stop的回调。 2 region_add回调 当添加内存区域时&…

Wireshark抓到的H264帧

H264文件解析 NALU size, NALU start code size, NALU type 0, 0 0 UNSPECIFIED NALU size, NALU start code size, NALU type 26, 4 7 SPS NALU size, NALU start code size, NALU type 4, 4 8 PPS NALU size, NALU start code…

浅谈数据孤岛和数据分析的发展

大数据时代&#xff0c;企业对数据的重视力度逐步增强&#xff0c;数据分析、数据治理、数据管理、数据资产&#xff0c;已经被人们熟知&#xff0c;在数据的统计汇总和挖掘分析下&#xff0c;管理者的决策有了强有力的支撑和依据&#xff0c;同时也产生了新的问题&#xff0c;…

CSS 奇技淫巧Box-shadow实现圆环进度条

CSS 奇技淫巧Box-shadow实现圆环进度条 文章目录CSS 奇技淫巧Box-shadow实现圆环进度条一、Box-shadow圆环进度条二、效果预览三、原理刨析四、实际应用五、总结六、参考资料&#x1f498;七、推荐博文&#x1f357;一、Box-shadow圆环进度条 实现圆环进度条的方法用很多种&am…

figma和sketch应该选择哪个?

设计行业的工具层出不穷&#xff0c;在我看来sketch它在一定程度上被颠覆了PS&#xff0c;如今sketch已经成为许多设计团队的设计工具。 那么Figma相对于Sketch自身优势是什么&#xff1f;有什么不便&#xff1f;让我们从几个方面来了解。 两个软件都很适合创建UI和组件库。Sk…

图形查看器丨IrfanView功能简介

IrfanView 是一款快速、紧凑和创新的图形查看器&#xff0c;适用于Windows XP、Vista、7、8、10和11。 IrfanView寻求创建独特、新颖和有趣的功能&#xff0c;与其他一些图形查看器不同&#xff0c;它们的全部“创造力”是基于功能克隆、窃取想法和来自ACDSee和/或IrfanView的整…

mac vscode安装dart

1.安装Dart 1.安装下载Dart的工具 官网&#xff1a;https://brew.sh/ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"如果遇到 zsh: command not found: brew /bin/zsh -c "$(curl -fsSL https://gite…

Vue.js

文章目录1、vue核心基础1.1、安装1.2、Hello Vue1.3、模板语法1.4、数据绑定1.5、el与data的两种写法1.6、理解MVVM模型1.7、Object.defineProperty方法1.8、数据代理1.9、事件处理2.0、事件修饰符2.1、键盘事件2.2、计算属性2.3、监视属性2.4、绑定样式2.5、条件渲染2.6、列表…

《计算机网络》——第五章知识点

可靠 保证接收方进程从缓存区读出的字节流与发送方发出的字节流是完全一样的。 确认重传不分家&#xff0c;TCP的发送方在规定的时间内没有收到确认就要重传已发送的报文段。 流量控制:让发送方慢点&#xff0c;要让接收方来得及接收。 TCP利用滑动窗口机制实现流量控制。 …

PCB电磁兼容设计1

PCB电磁兼容设计 20221229 关键元件 无源器件 模拟、逻辑器件 磁性元件 开关元件 连接器元件 多数情况&#xff0c;电路基本元件满足EMC程度将决定设备满足EMC的程度。 实际元件不是“理想”的&#xff0c;本身可能是干扰源或敏感设备。 选择合适的电子元件的主要准则包…

try/catch捕获不到的异常

try/catch捕获不到的异常捕获不到的异常这种情况finally块会执行吗&#xff1f;spring中的Transactional事务还会会滚吗&#xff1f;该如何捕获这种异常&#xff1f;Throwable可以看做是异常世界中的Object&#xff0c;在Java中所有异常都有一个共同的祖先&#xff1a;Throwabl…

Python 并行加速技巧分享

文章目录一、 使用joblib进行并行计算二、使用Parallel与delayed进行并行加速一、 使用joblib进行并行计算 作为一个被广泛使用的第三方Python库&#xff08;譬如scikit-learn项框架中就大量使用joblib进行众多机器学习算法的并行加速&#xff09;&#xff0c;我们可以使用pip…

【十天成为红帽工程师】第八天 学习编写playbook

目录 一、playbook编写要素 二、playbook编写前的准备 三、实验要求操作 一、playbook编写要素 &#xff08;一&#xff09;playbook位置可这样写&#xff1a;/ansible/chap1/play1.yml 文件后缀为.yml&#xff0c;以yaml格式编写的文本文件 文档开头标记--- 文档结束标…

加解密与HTTPS(2)

您好&#xff0c;我是湘王&#xff0c;这是我的CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e; 近些天由于完全放开&#xff0c;我也从“杨过”变成了“杨康”&#xff0c;加之家中亲人故去&#xff0c;所以长久未能更新&#xff0c;特此致歉&#xff5e; 上…