TS如何解决属性在另一个类型中不存在的问题?

2023-10-31

先来看一个例子:

export interface Cat {
  coatColor: string; // 毛色
  varieties: string; // 品种
  weight: number; // 体重
  meow: () => void; // 喵喵叫
}
export interface Dog {
  coatColor: string;
  varieties: string;
  weight: number;
  bark: () => void; // 汪汪叫
}

const getAnimalInfo = isCat ? getCatInfo : getDogInfo;
const animal = await getAnimalInfo<Cat | Dog>({name: 'kangshifu'});

let call;
if(isCat){
  call = animal.meow; 
  /* 报错,提示:
	类型“Cat | Dog”上不存在属性“meow”。
	类型“Dog”上不存在属性“meow”。
  */
} else {
  call = animal.bark;
  /* 报错,提示:
	类型“Cat | Dog”上不存在属性“bark”。
	类型“Cat”上不存在属性“bark”。
  */
}

该 Demo 由真实案例改编而来

现在我们假设,只能用一个变量来保存可能来自两个不同接口返回的数据,接口返回值类型已经设定为或的关系。

从变量中取某一个类型特有的属性时,便会提示在另一个类型中不存在该属性,应该如何解决?

目前个人已知有三种常用解决方案

1. 在变量取值时进行断言

let call;
if(isCat){
  call = (animal as Cat).meow; 
} else {
  call = (animal as Dog).bark;
}

当 Cat 或 Dog 特有属性较多时,就需要加非常多的断言,会使代码显得十分不优雅

2. 借助类型守卫

什么是类型守卫?

TS 在遇到以下这些条件语句时,会在语句的块级作用域内「收紧」变量的类型,这种类型推断的行为称作类型守卫 (Type Guard)。

  • 类型判断:typeof
  • 实例判断:instanceof
  • 属性判断:in
  • 字面量相等判断:=====!=!==

(这里列举常用的 4 种)
类型守卫可以帮助我们在块级作用域中获得更为精确的变量类型

这里就可以通过判断 animal 中是否存在 meow 属性,来确定变量是否为 Cat 类型的对象

let call;
if(isCat && 'meow' in animal){
  call = animal.meow; // 鼠标放到 animal 上,可以看到类型被限定为 Cat
} else if(!isCat && 'bark' in animal) {
  call = animal.bark; // animal 类型被限定为 Dog
}

个人并不是很推荐这种方式

真实的开发中,Cat 的特有属性往往有很多,不论使用哪个属性,似乎都在表示我们尝试以偏概全,至少代码看起来是这样的,就会显得十分不优雅

但不得不承认这也是一种非常好的限定类型的方法

‘meow’ 的值是 null 或 undefined 都会不影响 in 的判断,只要存在该属性均会返回 true

3. 将老变量赋值给被限定类型的新变量

let call;
if(isCat){
  const cat: Cat = animal;
  call = cat.meow;
} else {
  const dog: Dog = animal;
  call = dog.bark;
}

个人比较推荐第三种,大家也可以发表一下各自的看法,集思广益

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TS如何解决属性在另一个类型中不存在的问题? 的相关文章

  • 如何将 Django 中的数组传递给模板并在 JavaScript 中使用它

    我想将数组传递给模板 然后通过 JavaScript 使用它 In my views py I have arry1 Str 500 20 return render to response test html array1 arry1 在
  • 如何在bootstrap中默认隐藏侧边栏?

    我在这里有一个很好的参考 作为 Bootstrap 在设计 Web 表单应用程序时的侧边栏 http startbootstrap com template overviews simple sidebar http startbootst
  • Sonar 中的 javascript 代码覆盖率

    我是使用 Sonar 和插件进行 javascript 代码覆盖的新手 使用 Sonar 分析时 有哪些可能性可以找出 javascript 代码的质量 包括代码覆盖率 目前我正在使用 karma runner 它提供代码覆盖率报告 可以在
  • 在动态创建的元素上添加事件监听器[重复]

    这个问题在这里已经有答案了 是否可以向所有动态生成的元素添加事件侦听器 Javascript 我不是页面的所有者 因此我无法以静态方式添加侦听器 对于页面加载时创建的所有元素 我使用 doc body addEventListener cl
  • React 应用程序中的 addEventListener 不起作用

    一些背景 我正在尝试消费自定义网络组件在 React 应用程序中并尝试监听来自 Web 组件的事件 我相信您不能只在自定义 Web 组件上以通常的反应方式处理事件 i e
  • 如何在php中使用一张图像绘制形状

    我需要使用图像的一部分来创建帧图像 例如 用户将从后端上传图像片段 现在我需要根据前端用户的要求在前端创建一个框架 用户将选择框架的高度和宽度 然后他将选择该图像片段 如下所示 我没有办法做到这一点 我尝试通过 css 和 html can
  • 游戏手柄 JavaScript 未能按预期更新

    我正在尝试让浏览器报告我的 XBOX 控制器的状态 然而 在第一次按下按钮后 它似乎变得 卡住 我究竟做错了什么
  • 为什么我们使用 SpreadsheetApp.flush()?

    我的理解是 flush https developers google com apps script reference spreadsheet spreadsheet app flush有助于在功能发生时执行这些功能 而无需将它们捆绑在
  • 使 Material UI Grid 项目的子项拉伸以适合父容器的剩余高度

    1 现状 我有一个包含 4 个网格项的 Material UI 网格容器 每个 Grid 项中都有一个 Typography 组件 其中包含标题和包含一些内容的 Card 如下所示 2 期望的外观 我希望卡片填充网格项目的剩余高度并且不超过
  • 将 onclick 事件应用于页面加载时不存在的元素

    我将列表样式设置为看起来像选择框 并且当用户单击列表中的元素时我想触发一个函数 但是该元素是通过加载的AJAX因此 当页面加载并且我无法绑定时不存在onclick事件到它onDomReady 如果我把它作为一个普通的选择列表 我可以只标记一
  • 将 window.location 传递给 Flask url_for

    我正在使用 python 在我的页面上 当匿名用户转到登录页面时 我想将一个变量传递到后端 以便它指示用户来自哪里 发送 URL 因此 当用户单击此锚链接时 a href Sign in a 我想发送用户当前所在页面的当前 URL
  • 有没有办法伪造同步 XHR 请求?

    我正在使用 Emscripten 系统将一堆 C 代码移植到 Javascript C 代码有很多调用fopen这是一个同步 IO 调用 在 Emscripten 中 我们使用对本地资源的 XHR 请求来模拟这一点however 在 Fir
  • 如何使用 JavaScript 获取元素的填充值?

    我有一个textarea在我的 HTML 中 我需要获取整数或浮点形式的填充数值 以像素为单位 我如何使用 JavaScript 获取它 我没有使用 jQuery 所以我正在寻找纯 JavaScript 解决方案 这将返回padding l
  • 如何读取firebase推送通知内容并在ionic2中触发方法?

    是否可以访问push notificationionic 2 中的内容并在通知到达时执行一堆代码或event fire 我建议使用科尔多瓦插件 firebase https github com arnesson cordova plugi
  • JavaScript 提升解释

    下面的片段有什么区别 var a 0 function b a 10 return function a b console log a gt 10 and var a 0 function b a 10 return function a
  • 在方法内部执行方法

    我目前正在 FreeCodeCamp 中进行 JavaScript 练习 我的代码应该使用的测试用例之一是函数调用 如下所示 addTogether 2 3 这是我得到的基本功能 function addTogether return 当我
  • 搜索多维数组 JavaScript

    我有一个如下所示的数组 selected products 0 r1 7up 61 Albertsons selected products 1 r3 Arrowhead 78 Arrowhead selected products 2 r
  • D3 将现有 SVG 字符串(或元素)追加(插入)到 DIV

    我到处寻找这个问题的答案 并找到了一些我认为可能有用的资源 但最终没有让我找到答案 这里有一些 外部SVG http bl ocks org mbostock 1014829 嵌入SVG https stackoverflow com qu
  • 用javascript调用外部网页(跨域)

    我正在尝试使用以下网络服务来验证提要这个问题 https stackoverflow com questions 11996430 check if a url is a valid feed 但浏览器不允许我向另一台服务器发送 ajax
  • JQuery 删除和内存泄漏

    我正在开发一个游戏 我看到了很多内存消耗 我使用jquery animate 动画完成后 我 remove 元素 我的问题是 从 dom 树中删除一个元素后 对象还存在记忆中吗 Javascript 是一种垃圾收集语言 这意味着当没有代码保

随机推荐

  • 【流媒体协议】RTMP和RTSP的区别

    RTMP和RTSP都是常用的流媒体协议 支持推流和拉流 但是它们的特点不同 应用场景也不同 RTMP协议 全称Real Time Messaging Protocol RTMP将整个视频分割为多个小的片段进行传输 基于TCP 连接稳定 低延
  • Java基础--------网络编程

    参考http www cnblogs com xdp gacl p 3631965 html 点击打开链接 以此为模板 自己做了整理 修改 目录 一 网络的概念 二 网络通信协议及接口 2 1 通信协议分层思想 2 2 参考模型 三 IP
  • AD怎么设置相同网络的线宽

    一 对网络进行分类 快捷键 D C 在弹出的面板中找到 net class 单击右键 选择 Add Class 二 选择网络 选中Net Classes中刚刚建好的类POWER 按住CTRL键 在Non Members中选择5V 20V 先
  • 最强nba体验服显示服务器正在停机,最强NBA玩不了怎么办 游戏进不去玩不了原因分析及解决方法...

    对于一些刚下载好游戏的萌新玩家来说 最头疼的可能就是游戏进不去或玩不了了 那么最强NBA玩不了怎么办 不要慌 小编这就给大家分析下游戏玩不了或进不去的各种原因以及解决方法 类别 体育竞技 大小 471 34M 语言 简体中文 评分 10 最
  • golang for range循环坑

    比较两段代码 package main import fmt func main a int 1 2 3 4 5 6 7 8 9 for len a gt 0 a a 1 fmt Println a 输出 2 3 4 5 6 7 8 9 3
  • 分布式概念

    集群与分布式区别 集群 复制模式 每台机器做一样的事 分布式 两台机器分工合作 每台机器做的不一样 分布式好处 独立开发 部署 测试 易于扩展 复用性高 例如 所有的产品都可以使用该系统作为用户系统 无需重复开发 架构演进 架构演进一 早期
  • python 如何查看模块所有方法-Python查看模块(变量、函数、类)方法

    常用五种方法 前提是要先导入这个包 然后用下面的方法去查看 这名称 可是包 方法 或 类 1 help 名称 2 名称 doc 3 dir 模块名 List item 通过 dir 函数获取到的模块成员 不仅包含供外部文件使用的成员 还包含
  • PySide6/PyQT多线程之 高效管理多线程:暂停、恢复和停止的最佳实践

    前言 关于 PySide6 PyQT 多线程 正确地处理多线程编程并确保线程之间的同步和通信并不容易 本文以一个示例代码为基础 介绍 PySide6 PyQT多线程的运用 展示如何创建和管理线程 以及如何实现线程之间的同步和通信 设想这么一
  • python 切换root 执行命令

    如下 以创建系统用户举例 配置文件配置普通用户信息 登入后切换root用户 创建一个指定名字和密码的系统用户 def create user root pwd username password import paramiko result
  • STM32 RST管脚上拉后一直是0.1V左右的低电平,恶心,终于找到原因,焊锡膏啊

    给自己以后提醒 这次做的STM32平衡车的板子 发现仿真器一直烧写不进去 提示 core is held 先看魔术棒 排除了仿真器连接的问题 上网搜 core is held 原因 网友说应该是复位脚RST的电平没有拉高 但是我的原理图上已
  • 原码、反码、补码基本概念

    基本概念 原码 符号位加上真值的绝对值 也就是第一位表示符号 其余位表示值 0为正值 1为负值 原码是人脑最容易理解和计算的表示方式 反码 正数的反码是其本身 负数的反码是在其原码的基础上符号位不变 其余各位取反 一个反码表示的负数是无法无
  • Golang学习笔记:递归函数

    接前面java写的递归例子 还是计算一个数递减相乘 func test01 n int int result 0 if n lt 1 return 1 else result test01 n 1 n return result 执行一个函
  • IDEA个性化设置注释模板(详细版)

    IDEA设置注释模板 类注释模板 方法注释模板 效果展示 1 类注释模板 类注释模板是IDEA创建类时生成的注释 第一步 File gt Settings 第二步 Editor gt File and Code Templates gt I
  • 苹果核 - 页面动态化的基础 —— Tangram

    12月10日在SFDC SegmentFault Developer Conference 大会上初次介绍了手机天猫的Tangram方案 现场时间有限 讲得匆忙 特此整理记录 这篇内容是Tangram的整体介绍与相关业务开发实践的介绍 后续
  • 一网打尽当下NoSQL类型、适用场景及使用公司

    在过去几年 关系型数据库一直是数据持久化的唯一选择 数据工作者考虑的也只是在这些传统数据库中做筛选 比如SQL Server Oracle或者是MySQL 甚至是做一些默认的选择 比如使用 NET的一般会选择SQL Server 使用Jav
  • 图像处理:RGB与YCbCr

    简要概述一下RGB与YCbCr 方便记忆 RGB与YCbCr都是人为规定的色彩空间 同一种颜色既可以用RGB来表达 存储 也可以用YCbCr来表达 存储 就如同二进制数1111与十进制数15一样 形式不同但是表达的内容是相同的 1 RGB
  • ubuntu关机后无法进入系统

    原因 ubuntu提示内存不足后 关机扩容再次开机 黑屏卡死无法进入登录界面 解决 参考下面的博客 进入Ubuntu Linux Recovery Mode 删除一些目录 释放内存空间后 完美解决 ubuntu黑屏无法进入系统 Recove
  • 章节1 概述 - Segger SystemView使用手册(译文)

    本文博客链接 http blog csdn net bjr2016 作者 bjr2016 未经允许不得转载 1 概述 本节描述SEGGER SystemView的一般使用 1 1 SEGGER SystemView 是什么 SystemVi
  • selenium 网页自动化-在访问一个网页时弹出的浏览器窗口,我该如何处理?

    前言 相信大家在使用selenium做网页自动化时 会遇到如下这样的一个场景 在你使用get访问某一个网址时 会在页面中弹出如上图所示的弹出框 首先想到是利用Alert类来处理它 然而 很不幸 Alert类处理的结果就是没有结果 并不能够将
  • TS如何解决属性在另一个类型中不存在的问题?

    先来看一个例子 export interface Cat coatColor string 毛色 varieties string 品种 weight number 体重 meow gt void 喵喵叫 export interface