迭代对象时如何断言匹配类型?

2023-12-07

以下代码块会产生打字稿错误,因为尽管we我知道foo[k] and bar[k]是同一类型,TS 无法知道(好吧,也许通过某种魔法它可以,但显然它不知道)

interface IMixed {
    a: number;
    b: string;
    c: boolean;
}

const foo: IMixed = { a: 1, b: 'one', c: true };

const bar: IMixed = { a: 2, b: 'two', c: false };

(Object.keys(foo) as Array<keyof IMixed>).forEach(k => {
    foo[k] = bar[k]; 
//  ^^^^^^ Type 'string | number | boolean' is not assignable to type 'never'.
});

当 TS 无法弄清楚我知道的事情是真的时,我就会投射它。但在这种情况下,虽然我知道这是一个有效的分配,但我不知道它是什么类型......我只知道它们是相同的。我无法在这里找到一种使用泛型的优雅方法。

假设我致力于迭代这些属性的实践(比如说,因为我们期望属性确实被添加到行中,并且类似的代码存在于整个代码库中......)

简而言之:我如何断言此分配有效?

(附带问题:为什么错误将受让人称为“从不”类型?)

UPDATE

@captain-yossarian 对可变性提出了很好的观点,并提出了一个完全可行的不可变解决方案。不过,如果这个例子稍微复杂一些,我觉得这个问题仍然悬而未决:

interface IMixed {
    a: number[];
    b: string[];
    c: boolean[];
}

const foo: IMixed = { a: [1], b: ['one'], c: [true] };
const bar: IMixed = { a: [2], b: ['two'], c: [false] };

function intersection<T>(...arrays: T[][]): T[] {
    return [...new Set([].concat(...arrays))]
}

(Object.keys(foo) as Array<keyof IMixed>)
  .reduce((acc, elem) => ({
    ...acc,
    [elem]: intersection(foo[elem], bar[elem])
                      // ^^^^^^^^^ Argument of type 'string[] | number[] | boolean[]' is not 
                      // assignable to parameter of type 'string[]'.
  }), foo);

关键是,赋值显然要求类型兼容......但这也是如此intersection功能。所以这就像原始问题的不可变版本。


值得使用reduce代替forEach在这种情况下:

interface IMixed {
  a: number;
  b: string;
  c: boolean;
}

const foo: IMixed = { a: 1, b: 'one', c: true };

const bar: IMixed = { a: 2, b: 'two', c: false };

(Object.keys(foo) as Array<keyof IMixed>)
  .reduce((acc, elem) => ({
    ...acc,
    [elem]: bar[elem]
  }), foo);

操场

突变在 TypeScript 中效果不佳。

查看相关问题:first, second, third, forth and my article

UPDATE

(Object.keys(foo) as Array<keyof IMixed>).forEach(k => {
    foo[k] = bar[k]; // error
});

你这里有一个错误,因为forEachreduce是动态的。bar[k]是一个联盟number | string | boolean, 也foo[k]。这意味着在循环内部可以分配foo['a'] = foo['c']。这两个值都是有效的,因为我们期望一个并集number | string | boolean但这也是不安全的。这就是 TS 禁止这种行为的原因。

从另一方面,reduce有效,因为我们创建了扩展的新对象IMixed而不是变异

UPDATE

为了能够变异foo你需要添加indexing to IMixed界面:

type IMixed= {
  a: number;
  b: string;
  c: boolean;
  [prop: string]: number | boolean | string
}

const foo: IMixed = { a: 1, b: 'one', c: true };

const bar: IMixed = { a: 2, b: 'two', c: false };


(Object.keys(foo) as Array<keyof IMixed>).forEach(k => {
  foo[k] = bar[k];
});

操场

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

迭代对象时如何断言匹配类型? 的相关文章

随机推荐

  • JTextArea位置,setBounds不起作用?

    我想要一个JTextArea在某个位置上 我尝试了几件事 比如使用不同的LayoutManagers no LayoutManager无论如何 setLayout null 等等 无论我做什么 似乎setBounds setLocation
  • magento 网站迁移后 CSS 不加载

    我按照描述的步骤将我的 magento 网站迁移到不同的服务器here 一切都很顺利 除了当我加载页面时 CSS 不会加载 而且我只是以纯文本形式获取页面 我使用 firebug 并注意到系统用于获取 CSS 文件的路径在 FTP 服务器中
  • 在 BST 中查找所有小于 x 的数字

    我该怎么做 我不确定什么时候才能停止 bst 搜索 如果树的每个节点都有一个字段numLeft它告诉你它的左子树中有多少个节点 也计算它自己 然后你可以这样做O log N 继续添加即可numLeft对于每个值小于的节点的全局结果变量x c
  • 如何将 char* 转换为 TCHAR[ ]? [复制]

    这个问题在这里已经有答案了 char stheParameterFileName argv 1 I m passing the file name as a parameter TCHAR szName 512 我怎样才能转换char to
  • 大 og:提要中的图像

    我注意到 Facebook 有两种不同的方式在用户的提要中显示带有图像的开放图谱故事 一种是带有小图像以及旁边的标题和描述 example 一张带有更大的图像 其下方有标题和描述 example 按照教程 我能够生成大图像 然而 现在我要离
  • VBA复制网站数据

    有人可以帮助我指出如何通过 VBA 将特定数据从网站复制到 Excel 工作表的正确方向吗 我尝试使用宏记录器和网络查询 但它不断显示错误脚本 并且黄色箭头没有出现在我想要复制的部分 这是我要复制的网站http etfdb com etf
  • @googlemaps/markerclusterer:如何设置 maxZoom?

    我试图弄清楚如何设置 maxZoom 属性 我找到了可接受的参数列表 new MarkerClusterer map markers algorithm renderer onClusterClick 所以 我不想实现我自己的算法 我觉得默
  • PyQt4 - 将文件拖放到 QPushButton 中

    我认为标题是相当不言自明的 我正在努力创建一个小型独立应用程序 要求用户将音频文件拖放到按钮上 然后使用文件路径等将文件与硬件上的相应按钮关联起来 我已经遵循了大量的小部件拖放教程 我的朋友也遵循了列表的拖放教程 但是我开始相信这不能为按钮
  • 在单个链表中的任意索引处插入新节点

    我将如何创建一个函数 允许我在链表中 的任何索引处插入新节点 这是结构 struct node int data struct node next 这是函数 注意只有一个双指针 索引和数据参数 void insertN struct nod
  • “填充无效且无法删除”-这段代码有什么问题吗?

    每次我运行这个并加密时 输出都是可变的 当我尝试解密时 我收到 填充无效且无法删除 已经和这个斗争了一两天了 我很茫然 private static string strIV abcdefghijklmnmo The initializat
  • Break D3 每个循环没有标志

    考虑以下代码 circle each function d code 我怎样才能打破循环 是否有一种自然的 D3 方法可以打破 every 循环 我的意思是没有标志如下 var flag false circle each function
  • 如何在 dplyr 中对将 NA 放在第一位进行排序? [复制]

    这个问题在这里已经有答案了 考虑以下示例 require tibble require dplyr set seed 42 tbl lt data frame id letters 1 10 val c runif 5 NA runif 4
  • 致命错误:找不到“Google_Auth_AssertionCredentials”类

    我正在尝试将旧的 google api 迁移到新的 api 这样我就可以获取 google 分析数据 我正在尝试与this示例 但它会引发此错误 致命错误 找不到类 Google Auth AssertionCredentials 示例 p
  • ReactJS中的渲染函数

    快问 我正在学习react js 当我们创建组件时 我们在渲染函数中提供要渲染的组件的 html 模板 到目前为止 我只看到了带有非常小的 html 片段的小组件 但我只是想知道如果我们有一个带有巨大 html 模板的组件会发生什么 有没有
  • Core 3.0 更新后 Azure 函数停止工作

    该代码在 Core 3 0 Preview7 版本中工作 但更新到 3 0 Azure 函数后开始出现错误 如果我尝试访问构建器服务对象 则会出现错误 也无法调试问题 还尝试更新 Microsoft Extensions Dependenc
  • 等待 HTML5 视频加载

    我有一个视频标签 当我让用户从数据库中的多个视频中进行选择时 我会动态更改其来源 问题是 当我更改 src 属性时 即使我告诉它 视频也不会加载 这是我的代码 video attr src my video value ogg video
  • 更改我的 jquery mobile 主题会更改我的 css 样式

    我在网站上创建了一个可折叠集 看起来与此类似 div style margin auto padding top 50px padding bottom 20px div h2 span style font size 16px font
  • BSD 套接字 - 如何使用非阻塞套接字?

    我正在尝试使用非阻塞 TCP 套接字 问题是他们仍然在阻止 代码如下 服务器代码 struct sockaddr name char buf 80 void set nonblock int socket int flags flags f
  • 如何从 (SQLite) 数据库加载的 JTable 中插入、更新和删除项目

    我目前有 2 个类 一类显示 GUI 一类是从数据库获取项目 我的代码如下 此代码用于在我的 GUI 中显示 JTable public void table if SOMR tableCall true this columnNames
  • 迭代对象时如何断言匹配类型?

    以下代码块会产生打字稿错误 因为尽管we我知道foo k and bar k 是同一类型 TS 无法知道 好吧 也许通过某种魔法它可以 但显然它不知道 interface IMixed a number b string c boolean