澄清TypeScript中的 `satisfies` 操作符

图片

TypeScript 的 satisfies 运算符已经推出一段时间了,但它似乎仍然是一个可以用来澄清的混乱来源。

可以把 satisfies 看作是将类型赋给值的另一种方式。

在我们深入研究之前,让我们回顾一下如何赋值类型。

首先,有一个不起眼的“冒号注解”(我们使用这个听起来有点像医学术语的名字,因为这个概念在 TS 文档中并没有真正给出一个名字)。

:表示“这个变量总是这个类型”:

 
const obj: Record<string, string> = {};obj.id = "123";

当你使用冒号注解时,你声明了变量是该类型。

这意味着你赋值给变量的东西必须是该类型:

 
// Type 'number' is not assignable to type 'string'.const str: string = 123;

给变量赋予的类型可能比你最初赋予的类型更宽。

 
let id: string | number = "123";if (typeof numericId !== "undefined") {  id = numericId;}

当你想要有一个默认值,而这个默认值以后可能会被重新赋值时,这个方法非常有用。

但是冒号注释有一个缺点。

当使用冒号时,类型优先于值。

换句话说,如果你声明的类型比你想要的宽,你就被这个宽的类型困住了。

例如,在下面的代码片段中,你没有在routes对象上获得 autocomplete:

 
const routes: Record<string, {}> = {  "/": {},  "/users": {},  "/admin/users": {},};// No error!routes.awdkjanwdkjn;

这就是  satisfies 被设计用来解决的问题。

这意味着它能推断出最窄的可能类型,而不是你指定的更宽的类型:

 
const routes = {  "/": {},  "/users": {},  "/admin/users": {},} satisfies Record<string, {}>;// Property 'awdkjanwdkjn' does not exist on type// '{ "/": {}; "/users": {}; "/admin/users": {}; }'routes.awdkjanwdkjn;

satisfies  还能防止在配置对象中指定错误的内容。

因此,satisfies  和 冒号注解 同样安全。

 
const routes = {  // Type 'null' is not assignable to type '{}'  "/": null,} satisfies Record<string, {}>;

另一种为变量赋值的方式是使用 “ as ” 注解。

与  satisfies  和冒号注解不同,使用 “ as ” 注解可以让你对 TypeScript 说谎。

在这个例子中,你在IDE中看不到错误,但它会在运行时崩溃:

 
type User = {  id: string;  name: {    first: string;    last: string;  };};const user = {} as User;// No error! But this will break at runtimeuser.name.first;

这些谎言有一些限制——你可以给对象添加属性,但是你不能在基本类型之间转换。

例如,你不能强制 TypeScript 将字符串转换为数字......

除非你用那个怪异的“as-as”:

 
// Conversion of type 'string' to type 'number'// may be a mistake because neither type// sufficiently overlaps with the other.const str = "my-string" as number;const str2 = "my-string" as unknown as number;

下面是  as  的合法用法,它用于将对象转换为尚未构造的已知类型:

 
type User = {  id: string;  name: string;};// The user hasn't been constructed yet, so we need// to use 'as' hereconst userToBeBuilt = {} as User;(["name", "id"] as const).forEach((key) => {  // Assigning to a dynamic key!  userToBeBuilt[key] = "default";});

警告:如果你使用  as  作为注解变量的默认方式,那几乎肯定是错误的!

下面的代码看起来很安全,但是一旦你给 User 类型添加了另一个属性, defaultUser 就过时了,而且它不会显示错误!

 
type User = {  id: string;  name: string;};const defaultUser = {  id: "123",  name: "Matt",} as User;

还有一种方法可以给变量赋类型:

什么都不加。

这不是打字错误!

TypeScript 在推断变量类型方面做得很好。

事实上,大多数情况下,你根本不需要输入变量:

 
const routes = {  "/": {},  "/users": {},  "/admin/users": {},};// OK!routes["/"];// Property 'awdahwdbjhbawd' does not exist on type// { "/": {}; "/users": {}; "/admin/users": {}; }routes["awdahwdbjhbawd"];

总结一下,我们有四种方法来给变量赋类型:

  • 冒号注解

  • satisfies

  • as 注解

  • 不注解,让TS推断


由于有不同的方法来做类似的事情,它可能会让人们对何时使用何种方法感到有点困惑。

简单的用例是  satisfies  最适用的:

 
type User = {  id: string;  name: string;};const defaultUser = {  id: "123",  name: "Matt",} satisfies User;

但是大多数时候,当你想给变量赋一个类型时,你可能希望这个类型更宽。

如果这个例子使用的是 satisfies ,那么就不能把 numericId 赋给 id :

 
// colon annotationlet id: string | number = "123";if (typeof numericId !== "undefined") {  id = numericId;}// satisfieslet id = "123" satisfies string | number;if (typeof numericId !== "undefined") {  // Type 'number' is not assignable to type 'string'.  id = numericId;}

经验法则是,你应该只在以下两种特定情况下使用satisfies:

  • 你想要的是变量的精确类型,而不是宽泛类型。

  • 这个类型足够复杂,你需要确保你没有把它搞砸。

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

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

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

相关文章

【BUG】golang gorm导入数据库报错 “unexpected type clause.Expr“

帮同事排查一个gorm导入数据报错的问题 事发现场 ck sql CREATE TABLE ods_api.t_sms_jg_msg_callback_dis (app_key String DEFAULT COMMENT 应用标识,callback_type Int32 DEFAULT 0 COMMENT 0送达&#xff0c;1回执,channel Int32 DEFAULT 0 COMMENT uid下发的渠道,mode…

基于FFT + CNN -Transformer时域、频域特征融合的电能质量扰动识别模型

目录 往期精彩内容&#xff1a; ​模型整体结构 1 快速傅里叶变换FFT原理介绍 第一步&#xff0c;导入部分数据&#xff0c;扰动信号可视化 第二步&#xff0c;扰动信号经过FFT可视化 2 电能质量扰动数据的预处理 2.1 导入数据 2.2 制作数据集 3 基于FFTCNN-Transform…

无心剑中译聂鲁达《喜欢你寂静如斯》

I Like for You to Be Still 喜欢你寂静如斯 Pablo Neruda 帕布罗聂鲁达 I like for you to be still: it is as though you were absent, and you hear me from far away and my voice does not touch you. It seems as though your eyes had flown away and it seems that…

专业139总分400+南昌大学811信号与系统考研经验电子信息与通信工程集成电路

今年专业课811信号与系统139分&#xff0c;总分400&#xff0c;顺利上岸南昌大学&#xff0c;回首这一年的复习&#xff0c;有很多经验想和大家分享&#xff0c;希望对大家复习会有一些帮助。专业课&#xff1a;139分&#xff0c;811信号与系统 主要参考书&#xff1a;《信号与…

第二证券:苹果Vision Pro出货在即 固态电池产业化前景渐明

sion Pro即将于2月2日正式在美国商场开始交给&#xff0c;苹果美国官网释出了Vision Pro的详细参数&#xff0c;与发布会介绍根本一致&#xff0c;依靠总计12个摄像头、5种传感器、职业顶尖的单眼4K分辨率Micro-OLED显示屏、M2与R1芯片&#xff0c;完成了当时商场上独一无二的沉…

TCP/IP协议以及TCP/IP邮件详细介绍

目录 1. TCP/IP 协议 2. 协议族 3. TCP - 传输控制协议 4. IP - 网际协议&#xff08;Internet Protocol&#xff09; 5. HTTP - 超文本传输协议(Hyper Text Transfer Protocol) 6. HTTPS - 安全的 HTTP&#xff08;HTTP Secure&#xff09; 7. SSL - 安全套接字…

Leetcode2856. 删除数对后的最小数组长度

Every day a Leetcode 题目来源&#xff1a;2856. 删除数对后的最小数组长度 解法1&#xff1a;哈希 分类讨论 假设数组 nums 中元素 x 出现次数最多&#xff0c;其出现次数为 maxCount。 分类讨论&#xff1a; 如果 2 * maxCount > n&#xff0c;其余所有 n − maxC…

Mars3d实现【按当前相机视域页在地球上投射视频】功能

通过mars3d实现按当前相机视域页在地球上投射视频进行视频投射效果&#xff1a; 相关代码&#xff1a; // 按当前相机投射视频 export function startDrawGraphic2() {const ellipsoid map.scene.globe.ellipsoidconst canvas map.scene.canvasconst pt1 map.camera.pickE…

FluxMQ:新一代的高性能MQTT代理服务器

FluxMQ&#xff1a;新一代的高性能MQTT代理服务器 前言 FLuxMQ是一款基于java开发&#xff0c;支持无限设备连接的云原生分布式物联网接入平台。FluxMQ基于Netty开发&#xff0c;底层采用Reactor3反应堆模型&#xff0c;具备低延迟&#xff0c;高吞吐量&#xff0c;千万、亿级…

ClickHouse基于数据分析常用函数

文章标题 一、WITH语法-定义变量1.1 定义变量1.2 调用函数1.3 子查询 二、GROUP BY子句&#xff08;结合WITH ROLLUP、CUBE、TOTALS&#xff09;三、FORM语法3.1表函数3.1.1 file3.1.2 numbers3.1.3 mysql3.1.4 hdfs 四、ARRAY JOIN语法&#xff08;区别于arrayJoin(arr)函数&a…

创建自己的Hexo博客

目录 一、Github新建仓库二、支持环境安装Git安装Node.js安装Hexo安装 三、博客本地运行本地hexo文件初始化本地启动Hexo服务 四、博客与Github绑定建立SSH密钥&#xff0c;并将公钥配置到github配置Hexo与Github的联系检查github链接访问hexo生成的博客 一、Github新建仓库 登…

完整的 HTTP 请求所经历的步骤及分布式事务解决方案

1. 对分布式事务的了解 分布式事务是企业集成中的一个技术难点&#xff0c;也是每一个分布式系统架构中都会涉及到的一个东西&#xff0c; 特别是在微服务架构中&#xff0c;几乎可以说是无法避免。 首先要搞清楚&#xff1a;ACID、CAP、BASE理论。 ACID 指数据库事务正确执行…

小程序中picker多列选择器

需求&#xff1a;实现类似省市联动的效果&#xff0c;选择第一列后&#xff0c;第二列数据变化 html部分: <view class"section"><view>多列选择器</view><picker mode"multiSelector" bindchange"bindMultiPickerChange"…

大模型实践笔记(1)——GLM-6B实践

目录 在Ubuntu上的配置Git Large File Storage 安装Git LFS&#xff1a; 设置Git LFS&#xff1a; 使用Git LFS&#xff1a; 安装GLM-6B 环境依赖 ChatGLM2-6B介绍 配置GLM 下载代码 构建环境 安装依赖 本地部署 网页UI 很多模型在hugging face上面&#xff0c;…

Pudgy Penguins NFT 概览与数据分析

作者&#xff1a;stellafootprint.network 数据来源&#xff1a;Pudgy Penguins NFT Collection Dashboard “胖企鹅” Pudgy Penguins NFT 系列是由 8,888 个独特的企鹅头像组成的以太坊区块链项目。这个 NFT 项目能否在 2024 年达到发展的高峰&#xff1f; 关于 Pudgy Pe…

微信小程序新手入门教程三:基础语法介绍

WXML&#xff08;WeiXin Markup Language&#xff09;是框架设计的一套标签语言&#xff0c;可以与各种组件相结合&#xff0c;进行页面构建。 一 常用标签 wxml的语法结构与我们熟悉的html很像&#xff0c;但在细节处略有不同&#xff0c;我们可以参考html标签对比记忆。wxm…

12.scala下划线使用总结

目录 概述实践变量初始化导包引入方法转变为函数用户访问Tuple元素简化函数参数传递定义偏函数变长参数 结束 概述 实践 变量初始化 在Scala中&#xff0c;变量在声明时需要显式指定初始值。可以使用下划线为变量提供初始值&#xff0c;但这种语法仅限于成员变量&#xff0c;…

IDEA反编译Jar包

反编译步骤 使用IDEA安装decompiler插件 找到decompiler插件文件夹所在位置&#xff08;IDEA安装路径/plugins/java-decompiler/lib &#xff09;&#xff0c;将需要反编译的jar包放到decompiler插件文件夹下&#xff0c;并创建一个空的文件夹&#xff0c;用来存放反编译后的…

前端玩Word:Word文档解析成浏览器认识的HTML

前言 领导跟富文本编辑器杠上啦&#xff0c;领导有一个类似于某雀导入Word文档&#xff0c;解析内容后渲染到编辑器编辑的需求。某雀功能效果如下&#xff1a; 怎么搞定呢&#xff1f;自己写一个解析器&#xff1f; 本文分享Word文件转换成浏览器认识的HTML实战经验。 什么是…

springboot项目引入redis数据库的简单使用案例

springboot项目引入redis数据库的简单使用案例&#xff01;很多项目都需要使用到redis数据库&#xff0c;这是一个内存型的&#xff0c;非关系型数据库。它的读取速度非常快。因为存在了内存中。不是在硬盘中。而且它可以解决很多棘手的问题&#xff0c;比如&#xff1a;解决一…
最新文章