TypeScript 中交集和合并类型`{ foo } & { bar }` 和`{ foo, bar }` 的区别

Ped*_*o A 7 types typescript

考虑类型FooBar1FooBar2定义如下:

type Foo = { foo: string };
type Bar = { bar: number };
type FooBar1 = Foo & Bar;
type FooBar2 = { foo: string; bar: number };
Run Code Online (Sandbox Code Playgroud)

问题:FooBar1和 和有FooBar2什么不一样?


我的尝试/研究:

  • 它们可以双向分配给彼此!(手动检查并使用tsd-请参阅此处
  • 尽管如此,它们彼此并不相同!(检查tsd-请参阅此处
  • VSCode的智能感知不垮{ foo } & { bar }自动进入{ foo, bar },而它倒塌了其他复杂类型简单的形式,如NonNullable<string | undefined>string
// |------------------------------------------------------------|
// | let x: {                                                   |
// |     a: string;                                             |
// | } & {                                                      |
// |     b: string;                                             |
// | }                                                          |
// | -----------------------------------------------------------|
//  ^
//  | When hovering `x` here:
//  |
let x: { a: string } & { b: string };
Run Code Online (Sandbox Code Playgroud)

编辑: TypeScript 中扩展接口和交叉接口的区别?已被建议为重复,但我不同意。我不是将交集与接口的扩展进行比较,而是将交集与另一种原始类型进行比较,不涉及接口或扩展。

pir*_*-gh 3

在你的例子中,我们可以说 和FooBar1FooBar2相等的。我们确实可以证明:

type Equals<A, B> =
    A extends B
    ? B extends A
      ? true
      : false
    : false

type test0 = Equals<{a: 1} & {b: 2}, {a: 1, b: 2}> // true
Run Code Online (Sandbox Code Playgroud)

但对于一般性的答案,我们只能说它们并不总是相等。为什么?因为在某些情况下交叉点可以解析为never。如果 ts 发现交集有效,则继续处理,否则返回never

import {O} from "ts-toolbelt"

type O1 = {a: 1, b: 2}
type O2 = {a: 1} & {b: 2}       // intersects properly
type O3 = {a: 1, b: 2} & {b: 3} // resolved to `never`

type test0 = Equals<O1, O2>
// true

type test1 = O.Merge<{a: 1, b: 2}, {b: 3, c: 4}>
// {a: 1, b: 2, c: 4}
Run Code Online (Sandbox Code Playgroud)

这里类型O3解析为never因为bis3并且它不能与 重叠2。让我们更改我们的示例,以表明如果您具有以下条件,则交叉点将起作用:

import {A} from "ts-toolbelt"

type O4 = A.Compute<{a: 1, b: number} & {b: 2}> // {a: 1, b: 2}
type O5 = A.Compute<{a: 1, b: 2} & {b: number}> // {a: 1, b: 2}
Run Code Online (Sandbox Code Playgroud)

这个例子还强调了交叉点的工作原理——就像并集交叉点一样。TypeScript 将遍历所有属性类型并将它们相交。我们强制 TypeScript 计算与 的交集结果A.Compute

简而言之,如果 ts 不能与所有成员重叠,则该交集的乘积为never。因此,它可能不适合作为合并工具:

type O3 = {a: 1, b: 2} & {b: 3} // resolved to `never`
Run Code Online (Sandbox Code Playgroud)

所以记住,&它不是一个合并工具。仅当它们具有不重叠的键时才A & B等于。{...A, ...B}如果您需要合并类型,请使用O.Merge.