如何定义对象类型的真正逻辑或(结果中不混合不同的对象键)[重复]

2024-01-30

一个例子:

type TA = {a:number,b:number}
type TB = {a:number,c:number,d:number}
const t1:Or<TA,TB> = {a:1,b:1} // want
const t2:Or<TA,TB> = {a:1,c:1,d:1} // want 
const t3:Or<TA,TB> = {a:1,b:1,c:1} // DON'T want 

期望的结果是t1有效,因为它完全适合TA, and t2有效,因为它完全适合TB, 但对于t3无效,因为它也不完全适合TA or TB.

When

type Or<T,U>=T|U

TypeScript 实际上考虑了t3是有效的。 TypeScript 联合类型|还允许合并键对象,有时甚至部分对象。

将每种类型放入单个元素数组中,如下所示:

type T0 = {a:number,b:number}
type T1 = {a:number,c:number,d:number}
type Test=[T0]|[T1]
const t1:Test=[{a:1,b:1,}]  
const t2:Test=[{a:1,c:1,d:1}]  
const t3:Test=[{a:1,b:1,c:1}] // fails as desired

可以,但是被测试的对象也必须放置在单元素数组中。

有什么办法可以解决这个问题吗?


The Why

在打字稿中,|不是运算符*,它表示该类型是左侧类型和右侧类型的联合。如果您想了解原因,了解这一点很重要{a:number,b:number} | {a:number,c:number,d:number} allows {a:number,b:number,c:number}.

声明联合时,您告诉编译器可分配给联合的类型应该可分配给其中的至少一个成员。考虑到这一点,让我们检查一下{a:number,b:number,c:number}从这个角度键入。

联盟的左侧成员是{a:number,b:number},这意味着可分配给它的类型必须至少具有 2 个类型的属性number: a and b(有一个概念超额财产检查 https://www.typescriptlang.org/docs/handbook/interfaces.html#excess-property-checks对于对象字面量,但是,正如已经提及 https://stackoverflow.com/questions/66382997/typescript-how-to-define-a-true-logical-or-of-object-types-no-mixing-of-diffe#comment117358376_66382997作者:T.J.克劳德,这不适用于工会)。从手册 https://www.typescriptlang.org/docs/handbook/interfaces.html#our-first-interface**:

编译器仅检查是否至少存在所需的并且与所需的类型匹配

因此,自从{a:number,b:number,c:number}可分配给{a:number,b:number}不需要更多的检查 - 该类型至少满足联合的一项要求。顺便说一句,这种行为完全符合逻辑或的真值表,这类似于并集。


您尝试通过将类型包装到元组中来解决此问题依赖于裸露与包裹 https://stackoverflow.com/a/51651684/11407695类型参数行为。因为您将类型包装在元组中,所以编译器会比较tuples一种元素彼此的关系。显然,第三个元组与第一个和第二个元组不同,这给了您所需的结果。


The What

您真正想要的是逻辑异或所表现出的行为:其中之一,但不是两者。除了使用标记类型 https://mariusschulz.com/blog/tagged-union-types-in-typescript (提及 https://stackoverflow.com/questions/66382997/how-to-define-a-true-logical-or-of-object-types-no-mixing-of-different-object-k?noredirect=1#comment117358438_66382997作者:T.J. Crowder),我们可以定义一个实用程序,将一对类型转换为“来自 A 的所有 props 都存在于两个类型中,但不单独存在于 A 类型中”的并集:

type XOR<A,B> = ({ [ P in keyof A ] ?: P extends keyof B ? A[P] : never } & B) | ({ [ P in keyof B ] ?: P extends keyof A ? B[P] : never } & A);

这是它的工作原理(该实用程序的权衡是多余的属性被泄露给智能感知,但由于以下原因,人们立即不允许指定它never):

const t0:XOR<TA,TB> = {a:1} //property 'b' is missing
const t1:XOR<TA,TB> = {a:1,b:1} // OK
const t2:XOR<TA,TB> = {a:1,c:1,d:1} // OK 
const t3:XOR<TA,TB> = {a:1,b:1,c:1} // types of property 'c' are incompatible

操场 https://www.typescriptlang.org/play?#code/C4TwDgpgBAKgglAvFA3gQwFwDsCuBbAIwgCcAaA7fI4gXwFgAoUSWAISVU10JNIGNKPMgBNB1eg0bNoADQDyAJQA8cUqwB8HABQooAbSgAFKAEssUANYQQAewBmUBAF0oAfgxGoEAB7AIWYQBnS2t7KHZXRz1DFw8sCAA3EigaKAAycIBKKAAfKB19TzMQ2wd2F3dPHz8A4KtSxzdw6NioeKTiFPTHTIBuRkY+GyxA4ChgAAYMeWV4UhgNDnQMAEZUgHp1sGIbSGJQKAByAkPTYLwTQMCzAHNB4dHxlenFJTmFzWRllfJVjfWoHIANL3EZjYAAJhes1UHyWmB+Ah+ojWUE2gKBUFBj2AAGZoW9YYsvgjfoi-miAdJgmFtrsSAdDnxTmhiNAzEM8GA0MATAQADYQbHggAsBPexNQUAEEJSvUpFyut3GAAtoHYbPz+TYAO7Kul7XkQYJ2HZ4cbgaCHBaHDxoUhQYRAA


* 的概念|作为一名经营者存在于第一次修订 https://stackoverflow.com/revisions/66382997/1后来被删掉了

** 需要注意的是,这并不意味着all当找到匹配时检查短路。在这种情况下,联合体的所有成员本身都是对象文字,因此对已知属性的约束仍然适用于每个成员,如果在赋值期间存在未知属性,则会导致 TS2322 错误:

const t4:XOR<TA,TB> = {a:1,b:1,c:1, g:3} //Object literal may only specify known properties
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何定义对象类型的真正逻辑或(结果中不混合不同的对象键)[重复] 的相关文章

  • 安装 npm 包时自动安装类型定义

    有没有办法配置npm以这样的方式 每当我安装一个包时 它都会 检查里面是否有类型定义 如果没有 请尝试安装 types PACKAGE与 save dev flag 理想情况下 我希望这能够自动发生 作为插件或其他东西 而不需要编写限制 A
  • ES6 生成器——它们真的是 async/await 的替代品吗?

    评论区的帖子之一this http blogs msdn com b typescript archive 2014 10 22 typescript and the road to 2 0 aspx打字稿博客文章说 如果我必须等到 2 0
  • Typescript :过滤 keyof 类型参数

    我正在使用 typescript 3 8 3 并尝试动态查找某种类型的键并使用它们来生成其他对象 我有一个Detail对象并想用它来动态生成一个Column对象仅基于类型的属性Desc 这是我想做的事情的简化代码 Model interfa
  • TypeScript:实现具有调用签名和索引签名的接口

    我想创建一个满足此类型的对象 interface I string x string number 并通过 TypeScript 类型检查 理想情况下 我希望不需要诉诸技巧 例如使用any作为中间步骤 我知道可以将其他字段添加到具有调用签名
  • Angular2 authguards 执行异步函数失败

    我想通过检查用户是否从服务器登录来保护我的路由 但异步函数不会被执行 这是我的代码 canActivate route ActivatedRouteSnapshot state RouterStateSnapshot Observable
  • 访问 TypeScript 中默认无名类中的静态属性

    如果我定义一个这样的类 在一个名为 MyClass ts 的文件中 export default class static someProperty 1 someMethod var a someProperty 如何访问 someProp
  • 多重混合助手会导致意外的不可分配编译器错误。我做错了吗?

    我正在尝试输入一个多混合辅助函数 该函数接受构造函数的映射并返回用一些新接口扩展的那些构造函数的映射 考虑以下设计的基类 class Alpha alpha string alpha class Beta beta string beta
  • 无法打开 TypeScript 项目的扩展开发主机

    我正在尝试阅读第一个 VS Code 扩展教程 但无法打开扩展开发主机 按 F5 没有任何反应 单击调试侧栏中的开始按钮似乎也没有执行任何操作 我已经使用生成了我的项目yo code并选择了 TypeScript 选项 我尝试过选择 Jav
  • 如何在 inversify 中注入异步依赖?

    我有 TypeScript 应用程序并且正在使用反转 http inversify io 对于国际奥委会 我有一个连接类 use strict import injectable from inversify import createCo
  • 如何在 RxJS 订阅方法中等待

    在 RxJS 主题的订阅回调内部 我想要await on an async功能 下面是打字稿转译器抱怨的代码示例 错误 131 21 TS2304 找不到名称 await async ngOnInit this subscriber dat
  • 在 TypeScript 中将 Chai 自定义插件声明为 NodeJS 全局变量

    这是我之前的问题 https stackoverflow com questions 61676032 declare nodejs global variables in before hook in webdriverio using
  • 如何避免 TypeScript 中出现虚假的“未使用参数”警告

    我遇到过很多次这种情况 最后决定弄清楚正确的方法是什么 如果我有一个声明方法的抽象父类 然后一些具体子类在其实现中实现真正的逻辑 并且显然使用方法参数 但某些子类不需要在该方法中执行任何操作 因此不要使用方法参数 那些不必执行任何操作的方法
  • 如何在 Angular 2 应用程序中使 DateAdapter 单例?

    我正在开发一个带有延迟加载模块的 Angular 7 应用程序 我也使用有角度的材料组件 我想在日期选择器组件中本地化并支持多个区域设置 当应用程序语言发生变化时 我想在整个应用程序中全局更改它 可以通过 DateAdapter setLo
  • Typescript 模块解析的根路径

    我有两个使用打字稿的项目 一个是核心项目 moduleA 另一个是业务项目 moduleB 项目B使用项目A的模块 ts文件 位于 scripts文件夹 我想通过以下方式为projectB指定模块解析根文件夹projectA scripts
  • Angular 停止 Enter 键提交

    I am trying to stop the Enter from submitting my button and rather make it point to another function I tried trapping th
  • 在 TypeScript 中编译枚举

    What do enums 在 TypeScript 运行时变成 Fruit ts enum Fruit APPLE ORANGE main ts var bowl Fruit APPLE Fruit ORANGE console log
  • tsc-watch 是否消耗 TSC_NONPOLLING_WATCHER?

    我正在从事微服务集成项目 我使用同时运行 8 个打字稿服务tsc watch preserveWatchOutput onSuccess node build index js 即使我根本不编写源代码 这些进程也会消耗 70 的 CPU 我
  • 在 TypeScript 中实现类型安全的服务注册表

    我想要一个函数根据给定的标识符 例如字符串或符号 返回对象实例 在代码中它可能看起来像这样 define your services type ServiceA foo gt string const ServiceA foo gt bar
  • 来自另一个类的 Typescript 函数

    我对打字稿还很陌生 但现在我遇到了问题 我在每个类中都用 Typescript 编写了一个函数 function someFunction 现在我想从另一个 TS 文件调用该函数 我将其声明如下 declare function someF
  • 基于类属性的 Typescript 函数返回类型

    我有以下类和函数 class Test prop string otherProp number constructor const result doSomething

随机推荐