打字稿显示错误“对象可能是‘未定义’”

2023-12-05

我定义了一个由接口注释的多种费用的对象。该接口包括索引签名、只读属性和可选属性。当我声明计算总费用的函数时,TypeScript 警告我该对象可能未定义。因为我知道可选属性可以是未定义的,所以我使用类型保护来检查循环中每个属性的值是否不是未定义的。不幸的是,它不起作用。请帮我。下面是我的代码:

    interface FeeObjType2 {
      [index: string]: number | undefined;
      readonly book: number;
      food: number;
      vegetable: number;
      newBook?: number;
    }
    
    const feeObj2: FeeObjType2 = {
      book: 20,
      food: 14,
      vegetable: 13,
    };

    //ADD NEW PROPERTY TO THE CURRENT OBJECT
    feeObj2.newBook = 17;
    
    //FUNCTION TO CALCULATE THE TOTAL FEE
    const sumFunc = function (feeObj: FeeObjType2): number {
      let total = 0;
      for (const property in feeObj) {
        if (property && feeObj[property] !== undefined) {
          total = total + feeObj[property];**//The error takes place here!!!!!!!!!!!!!!!**
        }
      }
    
      return total;
    };

这是目前 TypeScript 的一个限制,如中所述微软/TypeScript#10530.


你期望通过检查feeObj[property] !== undefinedTypeScript 将narrow的类型feeObj[property] from number | undefined to undefined,但不幸的是这并没有发生。 TypeScript 通常允许这样的平等缩小关于属性访问,如下所示:

function works(feeObj: FeeObjType2) {
  const property = "someProp";
  feeObj[property] + 2; // error, possibly undefined
  if (feeObj[property] !== undefined) {
    feeObj[property] + 2; // okay
  }
}

这有效是因为property有字符串文字类型 of "someProp"。编译器知道该键的确切字面值。所以在你检查之后"someProp"的属性键feeObj for undefined,编译器会意识到它不能undefined在后续代码块中,并允许您将其视为number.

那么为什么下面的方法不起作用呢?

function doesNotWork(feeObj: FeeObjType2, property: string) {
  // (parameter) property: string
  feeObj[property] + 2; // error, possibly undefined
  if (feeObj[property] !== undefined) {
    feeObj[property] + 2; // still error, possibly undefined!
  }
}

这是因为类型property is string,即not文字类型,目前缩小行为仅适用于types属性键,而不是它们的身份。从类型系统的角度来看,上面的代码等同于:

function alsoBad(feeObj: FeeObjType2, property1: string, property2: string) {
  if (feeObj[property1] !== undefined) {
    feeObj[property2] + 2; // error of course
  }
}

在这里你正在检查feeObj[property1]然后访问feeObj[property2]。这是有道理的,这不安全,对吧?您可能会想“这当然不安全,因为property1 and property2可能不具有相同的值,而property显然具有相同的价值itself。”但是编译器没有跟踪键的身份,因此它不知道比较是与“自身”进行的。

进行同样的练习property1 and property2两者具有相同的文字类型"someProp",您会看到它再次开始工作:

function alsoGood(feeObj: FeeObjType2) {
  const property1 = "someProp";
  // const property1: "someProp"
  const property2 = "someProp";
  // const property2: "someProp"
  if (feeObj[property1] !== undefined) {
    feeObj[property2] + 2; // okay
  }
}

因此,目前,通过检查对象属性来缩小对象类型的唯一方法是检查已知文字类型的属性。


在这种情况下,建议的解决方法是在检查属性之前将其复制到新变量。这样你总是缩小同一个变量的范围:

const sumFunc = function (feeObj: FeeObjType2): number {
  let total = 0;
  for (const property in feeObj) {
    if (property) {
      const fp = feeObj[property]; // copy
      if (fp !== undefined) { // check
        total = total + fp; // okay
      }
    }
  }
  return total;
};

当然,在特定的示例中,您不需要如此冗长:没有真正的理由要检查property为了真实(如果有人写feeObj2[""] = 123, 你会really想要将其从总和中排除吗?);你可以替换x = x +加法赋值运算符 (+=);您可以使用零值合并 (??) 操作员处理undefined而不是有一个单独的代码块。这给你:

const sumFunc = function (feeObj: FeeObjType2): number {
  let total = 0;
  for (const property in feeObj) {
    total += feeObj[property] ?? 0; 
  }
  return total;
};

其行为应该类似,而不需要依赖于缩小范围feeObj[property] at all.

Playground 代码链接

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

打字稿显示错误“对象可能是‘未定义’” 的相关文章

  • 角度2中未定义的值

    我正在创建一个应用程序 在其中使用 Ag Grid api 在网页上列出我的数据库内容 Ag grid 有一个预定义的 api 来获取所选行的内容 这是我的代码 export class customer entryComponent pu
  • 单击上一页的按钮路由到该页面后如何刷新页面

    我有 2 个页面 一个主页和一个页面 2 当我单击主页上的按钮时 它会路由到 page2 现在 单击主页上的按钮后 当我到达第 2 页时 它应该刷新 因为我的项目中存在一些缓存问题 我在ngoninit上添加了window location
  • 渲染作为 Prop 传入的 Component

    我怎样才能渲染一个StyledComponent它是作为道具传入的吗 我正在传递一个Spinner组件到我的BarComponent作为渲染的道具 我尝试使用 this props icon in my BarComponent在下面的示例
  • 警告:找不到父级 tsconfig.json

    我想修复警告 警告 找不到父级 tsconfig json 在打字稿中Errors tab in IntelliJ IDEA 2016 3 我的 TypeScript 代码位于src目录和我的 TypeScript 输出将是lib正如预期的
  • 想要动态处理与分页相关的页码显示:ReactJS

    我有一些分页逻辑工作得很好 唯一的问题是我只能让它显示并固定数量的页面可供选择 现在我已经把它放到了 5 页 但我希望它能够根据总记录动态更改 假设我有 100 条记录 每页限制为 10 条 将有 10 页 现在我只能让它以这种方式显示 第
  • webpack TS2304 找不到名称“Map”、“Set”、“Promise”

    我有以下 webpack config js var path require path var webpack require webpack module exports entry ng2 auto complete path joi
  • 在 Typescript 中隐式创建一个元组

    有没有一种方法无需类型提示即可在 Typescript 中创建元组 如果我只是这样做 const tuple 1 2 元组的类型number 我能得到的最接近的单线是 const tuple number number 1 2 我错过了什么
  • 如何声明具有可变数量属性的 TypeScript 接口?

    这是一个简单的问题 令我惊讶的是我在任何地方都找不到明确的答案 我正在制作一个 API 需要定义一个可以具有多个 字符串 属性的接口 但没有设置属性数量 也没有设置它们的名称 但它们都必须具有字符串值 因此以下所有对象都将与该类型匹配 sl
  • Angular - 在一个组件中定义的函数,它生成动态子组件,不能在单独的非相关组件中调用

    更新到此这个新问题 https stackoverflow com questions 73987046 angular dynamically adding removing multiple instances of a single
  • CSF3 中的 Typescript 支持

    我正在使用 CSF3 编写故事 并且我想正确注释我的故事 我用谷歌搜索过 基本上找不到答案 我尝试过一些技巧here https github com storybookjs storybook issues 7677但没有任何效果 我发现
  • 使用 Vite 和 React 进行生产构建时出错:Uncaught TypeError 中的错误:_ 不是函数

    我在我的网站上使用 Vite React React Router 和 TypeScript 我在运行生产构建时遇到问题 在开发模式下一切正常 使用生产版本时 我的浏览器显示白色背景 并且在浏览器控制台中出现以下错误 上面的链接将我带到第
  • 使用 TypeScript 3 项目引用时出现“找不到模块”错误

    我想得到TypeScript 3 的项目参考正在工作 但很难从引用的项目中导入函数 我有一个ProjectA引用Shared 这是文件结构 ProjectA src person ts tsconfig json Shared src ut
  • Typescript 从 CDN 导入 .js

    在我的 ts 文件中 我想引用 js 由第三方托管 并使用 js 文件中的一些函数 到目前为止 我发现如何做到这一点的唯一方法是修改 html 页面并插入 ts 本身的标签 除了修改 html 页面之外 还有其他更优雅的方法吗 听起来您正在
  • RxJ 从 observable 中获取价值

    在组件中 singleEvent Observable
  • Angular 2 中的变更检测

    我正在将角度 1 和角度 2 集成在一起 因此我有角度 1 控制器和服务以及角度 2 组件 这些对于数据检索和存储来说工作得很好 反之亦然 下面是我的 html 页面 h3 Angular 1 service h3 div div
  • 打字稿中的递归未定义

    我在组件内使用画布对象来生成图表 为了使其动画化 我递归地调用该方法 我不断收到错误消息 指出该方法未定义 不确定我需要如何构建它 任何帮助表示赞赏 Animate function protected animate draw to Cl
  • TypeScript:增强内置类型

    如何增强其中一种 内置 类型 例如数组 在 JS 中 我会做类似的事情 Array prototype shuffle function TypeScript 中的等价物是什么 TypeScript 中的类型是 开放式 的 所以你可以这样写
  • 打字稿中枚举声明中的方括号的含义是什么?

    我正在浏览一个名为 Angular ngrx 项目的打字稿文件collection ts在那里 我看到声明了以下枚举常量 import Action from ngrx store import Book from models book
  • 用输入字段 Javascript/Angular2 替换某些单词

    我有一根绳子 我喜欢橙色 蓝色 黑色 粉色 玫瑰色 黄色 白色 黑色 是否可以用输入字段替换黄色和黑色 以便我可以输入自己的颜色 const a string I like orange blue black pink rose yello
  • cordova-plugin-geolocation watchPosition() 方法不起作用

    我正在开发 Ionic2 Angular2 Typescript 应用程序 我正在尝试使用 Cordova 的 Geolocation 插件 但是当我像这样调用 watchPosition 方法时http ionicframework co

随机推荐

  • MySQL:带有 ORDER BY COUNT 的 GROUP_CONCAT?

    这可能吗 假设我有一个地址列表 其中有很多重复的条目 我需要过滤掉所有重复项 因为有些地址的名称略有不同 但邮政编码和电话号码相同 首先 我对邮政编码和电话进行 GROUP BY SELECT name address postalcode
  • 如何使用 AWS Cloudformer 为现有 API 网关创建云形成模板?

    我已经使用 aws 控制台创建了一个 api 网关 我想使用以下方法为我的 api 网关生成 CloudFormation 模板云形成者 请帮忙 尽管 AWS 尚未发布官方声明 但 CloudFormer 似乎已终止生命周期 AWS 没有正
  • 使用正则表达式匹配编辑(重新编码、折叠、排序)因子级别

    我发现在 R 中操作因子变量过于复杂 清洁因素时我经常想做的事情包括 排序级别 不仅设置参考类别 而且将所有级别按逻辑 非字母顺序 排列为汇总表 x lt factor x levels new order 重新编码 重命名因子级别 简化名
  • iOS 中 NSOperation 和 NSOperationQueue 的后台任务

    我想上传一些文件 即使应用程序进入后台 这些文件也应该继续 目前 我正在从数据库检索文件 然后通过 NSOperation 将其添加到队列中 然后启动上传过程 即使应用程序进入后台或前台 也应上传所有文件 下面是单个任务的代码 任何人都可以
  • 如何找到 log4j 默认初始化中使用的 URL?

    Log4j默认初始化通过一个过程来查找并使用 URL 进行配置 之后 您如何才能找出最终使用的 URL 而无需自己编写相同的过程 如果您必须自己编写代码 您可能不会得到与 log4j 完全相同的结果 而且它可能会在未来的版本中发生变化 如果
  • 如何使用 Rails 发送电子邮件

    这可能非常直接和简单 但我是 ruby on Rails 的新手和菜鸟 我有一个简单的电子邮件 php 脚本 我在旧网站上使用过 但现在由于我已经转换为 Rails 我不确定如何创建与之等效的脚本 我尝试使用rails generate m
  • 为什么 echo 与 printf 结合显示错误的输出? [复制]

    这个问题在这里已经有答案了 有谁知道为什么当我执行此操作时 usr bin php 我明白了 1005 1005 1005 1005 1005 1005 你在混合echo and printf printf返回格式化字符串的长度 所以你的e
  • django-nonrel 和管理页面

    我正在尝试在 AppEngine 上为我的网站设置 Django 管理套件 但它不起作用 我正在使用 django nonrel 设置与 我网站的其余部分似乎工作正常 但我需要让管理员工作 以便我可以开始使用数据存储区 这是我得到的错误 D
  • 格式化 Emacs 函数中的标头以将缓冲区打印到 PDF(带换行)

    Rupert Swarbrick 提出了以下三个函数来将 Emacs 缓冲区打印为 pdf 其中行被换行 使用时通常不会出现这种情况 ps print 功能 问题是这个函数要实现换行 必须复制当前缓冲区 这有效地破坏了ps print bu
  • 使用C将exec进程发送到后台?

    我的问题听起来与此相同 但事实并非如此 在Linux中用C在后台启动一个进程 我知道如何执行 fork 但不知道如何将进程发送到后台 我的程序应该像一个简单的命令 unix shell 一样工作 支持管道和后台进程 我可以做管道和叉子 但我
  • Selenium WebDriver 获取文本

    我有一个 div 0 div 我尝试编写 myDiv 的测试0其中的文字 使用 WebDriver 是 String text webDriver findElement By xpath div name myDiv getText 但在
  • 通过单点登录进行身份验证后移至 Facebook 应用程序页面

    我正在开发一个应用程序 需要集成 Facebook 的社交功能 我想要的是使用 SSO 单点登录 功能 当用户按下我的应用程序中的按钮时 网络视图将打开并向他显示我在 Facebook 中的应用程序页面 在用户进行身份验证后 现在他可以像其
  • React WebApp 调用 NestJS 后端中使用 PassportStrategy 的 Google 登录无法正常工作

    我已经在 NestJS 后端中使用 PassportStrategy 实现了 Google 登录 NestJS 后端开发基于此指南 https medium com nielsmeima auth in nest js and angula
  • 类中ShouldSerialize()的重构...我可以使用IContractResolver吗?

    我有一个返回大量汽车功能的 API 全部都是布尔值或整数 基本上我只想显示返回真值或整数 gt 0 的 API 我正在使用 JSON net 因此我可以使用 ShouldSerialize 属性来确定是否应该根据属性的值序列化该属性 我的代
  • Django cookie 没有保存在浏览器上

    我正在使用 React 和 Django 制作一个应用程序 当我使用 django 登录时 我在 cookie 中设置了令牌 但浏览器中未设置 Django 响应 cookie 我试图努力调试它但不能 不知道我哪里做错了 Request U
  • 如何在 jQuery UI Slider 设置 3 种不同的颜色

    我正在用这个用户界面滑块 我必须用 3 种不同的颜色来制作这个滑块 手柄颜色 句柄的前一部分 句柄的下一部分 Something like this 到目前为止 我只能设置手柄颜色 但是 如何设置另外两种不同的颜色 一个用于手柄的前一部分
  • 循环多维数组并删除某些键

    我有一个基于下面数组的嵌套树结构 Array 1 gt Array id gt 1 parent gt 0 name gt Startpage uri gt 125 basename gt index php child gt 23 gt
  • 使用外部库将 Jar 转换为 exe

    我一直在尝试将 jar 转换为 exe 该程序 jar 使用蓝牙库 Bluecove 它是某个目录中的另一个 jar 该程序还使用 Java Swing 通常JFrame和东西 当从 Netbeans 或 Eclipse 中运行时 该程序可
  • TypeScript 类型排除泛型参数为“any”的类型

    这是一个分支React FunctionComponent 的 TypeScript 类型恰好返回一个 IntrinsicElement React 定义 declare namespace JSX type Element React R
  • 打字稿显示错误“对象可能是‘未定义’”

    我定义了一个由接口注释的多种费用的对象 该接口包括索引签名 只读属性和可选属性 当我声明计算总费用的函数时 TypeScript 警告我该对象可能未定义 因为我知道可选属性可以是未定义的 所以我使用类型保护来检查循环中每个属性的值是否不是未