使用类型保护时出现奇怪的范围问题

2023-11-30

假设我们有这样的打字稿代码:

interface A { 
  bar: string;
}
const isA = <T>(obj: T): obj is T & A => {
  obj['bar'] = 'world';
  return true;
}

let obj = { foo: 'hello' };
if (!isA(obj)) throw 'wont ever throw'

obj.foo // This is ok
obj.bar // This is ok

Array(5).fill(0).forEach((_, i) => {
  obj.foo // This is ok
  obj.bar // This is not ok
});

Why is obj.bar在内部时无效forEach?

打字稿游乐场


一般的答案是,在这种情况下你比编译器更聪明。 TypeScript 使用启发式方法分析控制流程尝试推断表达式的更窄类型的代码。它在这方面做得很合理,但是它并不完美也许永远不可能。

当您访问obj.bar抛出后立即 ifisA(obj)回报false,编译器缩小范围obj包括A,如您所料。不幸的是,当您创建一个闭包并将其传递给Array.prototype.forEach(),编译器加宽obj返回到其原始类型,其中不包括A。现在你和我都知道了forEach()将立即调用其回调函数,但 TypeScript 不会。就其所知,其价值obj将在调用回调之前进行修改。并且没有办法tell编译器不同。因此它认为缩小范围不安全并放弃。

所以,解决方法:一个想法是obj a const而不是声明它let:

const obj = { foo: 'hello' };
if (!isA(obj)) throw 'wont ever throw'
Array(5).fill(0).forEach((_, i) => {
  obj.bar // This is okay now
});

这实际上并没有改变这样的事实obj.bar可以在关闭的回调之前添加或删除obj被称为,但 TypeScript 使用的启发式类似于“const更有可能是不可变的let“, 虽然事实并非如此.

类似的解决方法,如果你不能obj a const,就是分配一个新的const缩小范围后的变量,并在回调中使用它:

let obj = { foo: 'hello' };
if (!isA(obj)) throw 'wont ever throw'
const myObj = obj;    
Array(5).fill(0).forEach((_, i) => {
  myObj.bar // This is okay
});

当然,出于这个原因,您最好跳过obj完全中间人:

let obj = { foo: 'hello' };
if (!isA(obj)) throw 'wont ever throw'
const bar = obj.bar;    
Array(5).fill(0).forEach((_, i) => {
  bar // This is okay
});

由你决定。希望有帮助。祝你好运!

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

使用类型保护时出现奇怪的范围问题 的相关文章

随机推荐

  • 将geojson标记加载到mapbox中设置自定义图标图像

    我是mapbox 传单的新手 我认为这是一个非常基本的问题 我在过去的两天里一直在努力解决这个问题 尽管我尝试了几种方法 但我无法解决这个问题 我通过 geojson 加载标记 var ma 3 L mapbox featureLayer
  • 检测和响应任何多边形内的球与墙碰撞

    需要编写良好的方法来检测和响应任何多边形内的球与墙的碰撞 例如 我有一个方法可以绘制一个在矩形内飞行的球 ctx beginPath ctx arc x y ballRadius 0 Math PI 2 ctx fillStyle 0095
  • Jasper 子报告未显示

    我有一份主要报告 调用2个不同的子报告两次 每次使用不同的参数 问题是显示不正确 LETTEROFACK TRANSF LTR 根本不来
  • 将数组从 php 发送到 python

    我正在尝试将一个数组从 php 传递到 python 由于某种原因 当我加载 php 页面时 我遇到了麻烦 所以如果人们建议我尝试不同的方法或者如果人们发现一个简单的方法 我将非常感激我在这里失踪了错误 因为我已经尝试这样做几个小时了 Th
  • 新工作表上的 VBA 数据透视表

    我已经录制了一个宏来在 VBA 中创建数据透视表和后续图表 它就像一种魅力 只是完全不是我需要的那样 问题是我希望能够运行代码并让它在尚不存在的工作表上创建一个表 基本上我将通过菜单上的按钮运行它 它应该在新页面上创建表格和图表 无需进一步
  • 从 Access 数据库收集数据

    我想从 Access 数据库的某些表中收集一些数据 我在网上找到了一些解决方案 但我还没有找到填充数据表或数据集并正确获取每个字段的方法 对我来说 获取整个表然后只获取我想要的信息是否更容易 或者我应该在访问数据库中进行大量搜索 每次只获取
  • 调试 PDO mySql 将 NULL 插入数据库而不是空

    我正在尝试使用 PDO 将 NULL 动态插入数据库 表结构 CREATE TABLE IF NOT EXISTS Fixes Id int 11 NOT NULL AUTO INCREMENT COMMENT PK CurrencyId
  • 没有名为 pkg_resources 的模块

    我正在将 Django 应用程序部署到开发服务器 并且在运行时遇到此错误pip install r requirements txt Traceback most recent call last File var www mydir vi
  • 当矩形与另一个矩形重叠时 OpenCV 连接轮廓

    我有以下输入图像 我的目标是绘制红色区域的轮廓 为此 我有以下代码 导入CV2 Read image src cv2 imread images jpg cv2 IMREAD GRAYSCALE Set threshold and maxV
  • IntelliJ IDEA Grails 没有看到 Jar

    我试图在 Linux 系统上的 Grails 项目中引用 IntelliJ IDEA 9 0 2 中的类 我将依赖项添加到BuildConfig groovy dependencies specify dependencies here u
  • “Substring” GridView BoundField 对象

    谁能告诉我如何对 GridView BoundField 对象进行子字符串化 到目前为止我已经尝试过了 但还没有成功 谢谢
  • 实体框架一对一映射问题

    使用VS 2010 beta 2 ASP NET MVC 我尝试创建一个实体框架文件并从数据库中获取数据 关系存在一些问题 因此我开始进行调整 但对于简单的一对一关系 我不断收到以下错误 错误 1 错误 113 多重性在关系 FK User
  • SWFTools 分段错误

    使用 swftools 中的 pdf2swf 将 PDF 转换为 SWF 时 出现分段错误 核心转储 错误 有没有人遇到过这个或知道可能出了什么问题 我在错误发生之前收到的通知是 NOTICE File contains jpeg pict
  • Google API - 每次都强制授予权限

    我正在使用 Google API PHP 客户端 每次我尝试登录时 我都被迫向应用程序授予权限 下面是我的代码 我基本上是访问 Google API for Analytics require once lib apiClient php
  • cvReprojectImageTo3D -2d 图像的 3d 建模问题 -

    我非常需要你关于这个问题的帮助 我正在尝试用 2D 图像对一个简单的场景进行 3D 建模 我使用 2 张图像 左 右 著名的筑波场景 http www cc gatech edu classes AY2003 cs7495 fall Pro
  • php 警告:strtotime() 错误

    我已将 joomla 和 wordpress 文件从旧服务器更改为新服务器 在前端和管理端 它的工作没有任何错误 但在数据库 phpmyadmin 部分它显示了一些像这样的警告消息 Warning strtotime function st
  • Post/Put 请求的路由错误(乘客标头)

    我遇到了一个奇怪的问题 经过一系列研究后无法更接近 我有几个通过 Carrierwave 上传文件的表单 当我上传信息时 部分路线被切断 我认为 例如 我有一个多部分表单提交到 https domain programs 223 add f
  • 线性回归 scala.MatchError:

    在 Spark 1 6 1 和 2 0 中使用 ParamGridBuilder 时出现 scala MatchError val paramGrid new ParamGridBuilder addGrid lr regParam Arr
  • SwiftUI:更新变量时导航链接会弹出

    我遇到这样的问题 更新变量时导航链接会弹出 这有点令人困惑 因为这种行为不会发生在应用程序的其他地方 但我正在做同样的事情 首先 有一个符合可识别性的 Vehicle 结构 在内容视图中 它显示在滚动视图中的 NavigationView
  • 使用类型保护时出现奇怪的范围问题

    假设我们有这样的打字稿代码 interface A bar string const isA