我有这种类型

type Cartesian = { kind: 'cartesian'; x: number; y: number; }
type Polar = { kind: 'polar'; angle: number; distance: number }
type Movement = { name: string } & (Cartesian | Polar);

我可以这样使用

const move = (movement: Movement) => { /* whatever */ };
move({ name: 'top right', kind: 'cartesian', x: 10, y: 10 });
move({ name: 'left', kind: 'polar', angle: Math.PI, distance: 10 });

但出于某种原因,我不能这样使用它

const unnamedMove = (unnamedMovement: Omit<Movement, 'name'>) => {
    move({ name: 'default', ...unnamedMovement })
}

因为TS抛出2345:

Argument of type '{ kind: "cartesian" | "polar"; name: string; }' is not assignable to parameter of type 'Movement'.
  Type '{ kind: "cartesian" | "polar"; name: string; }' is not assignable to type '{ name: string; } & Polar'.
    Type '{ kind: "cartesian" | "polar"; name: string; }' is missing the following properties from type 'Polar': angle, distance

我不明白这一点.

如果我没有弄错的话,Omit<Movement, 'name'>应该相当于Cartesian | Polar型的联合体,这将使{ name: 'default', ...unnamedMovement }成为Movement,所有的东西都应该工作.

然而,看起来TS推断Omit<Movement, 'name'>就像它是联合类型Cartesian & Polar一样,因此是错误的.

这是我的错误还是错误?

playground link

推荐答案

你可能想要Distributive conditional types个.从文档中

When conditional types act on a generic type, they become distributive when given a union type.

这意味着你可以这样声明

type DOmit<T, K extends string> = T extends any
  ? Omit<T, K>
  : never;

然后像这样使用

const unnamedMove = (unnamedMovement: DOmit<Movement, "name">) => {
    move({ name: 'default', ...unnamedMovement })
}

Playground here

Javascript相关问答推荐

如何使用合并排序方法编写数组排序Polyfill

回归函数不会迭代到foreach中的下一个元素

导入图像与内联包含它们NextJS

v-textfield的规则找不到数据中声明的元素

自定义帖子类型帖子未显示在网站上

使用typeof运算符获取对象值类型-接收字符串而不是数组

获取加载失败:获取[.]添加时try 将文档添加到Firerestore,Nuxt 3

如何最好地从TypScript中的enum获取值

我应该绑定不影响状态的函数吗?'

将现场录音发送到后端

当点击注册页面上的注册按钮时,邮箱重复

如何在模块层面提供服务?

闭包是将值复制到内存的另一个位置吗?

Rxjs流中生成IMMER不能在对象上操作

每次重新呈现时调用useState initialValue函数

FireBase云函数-函数外部的ENV变量

postman 预请求中的hmac/sha256内标识-从js示例转换

JavaScript将字符串数字转换为整数

使用API调用的VUE 3键盘输入同步问题

无法使用npm install安装react-dom、react和next