Typescript Omit 似乎将并集转换为交集

Nin*_*liu 2 javascript typescript union-types intersection-types

我有这个类型

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

我可以这样使用

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 });
Run Code Online (Sandbox Code Playgroud)

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

const unnamedMove = (unnamedMovement: Omit<Movement, 'name'>) => {
    move({ name: 'default', ...unnamedMovement })
}
Run Code Online (Sandbox Code Playgroud)

因为 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
Run Code Online (Sandbox Code Playgroud)

我不明白这一点。

如果我没有记错的话Omit<Movement, 'name'>应该相当于 union type Cartesian | Polar,这将使得{ name: 'default', ...unnamedMovement }a Movement,并且所有事情都应该起作用。

但是,看起来 TS 推断出Omit<Movement, 'name'>它是联合类型Cartesian & Polar,因此出现错误。

这是错误还是我的错误?

游乐场链接

Rad*_*iță 7

您可能需要分布式条件类型。来自文档

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

这意味着你可以声明这样的东西

type DOmit<T, K extends string> = T extends unknown
  ? Omit<T, K>
  : never;
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它

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

游乐场在这里


归档时间:

查看次数:

759 次

最近记录:

2 年,10 月 前