打字稿:了解并集和交集类型

Typescript: understanding union and Intersection types

我试图在 typescript 中获得关于 Union 和 Intersection 类型的直觉,但我无法弄清楚这种情况:Playground Link

interface A {
    a: number;
}

interface B{
    b: boolean;
}



type UnionCombinedType = A | B;
type IntersectionType = A & B;

const obj: UnionCombinedType = {
    a: 6,
    b: true,
}

const obj2: IntersectionType = {
    a: 6,
    b: true,
}

为什么允许我将两个值都放在交集类型中?两个接口之间的交集是空的。如果我将 & 读为 AND 那么我很清楚为什么它允许我添加两个道具,但是我应该将 | 关键字读为 OR 我会希望它允许我只分配 ab 但不能同时分配。

有人能给我一些关于这些类型的直觉吗?

鉴于以下情况:

interface A {
    a: number;
    c: number;
}

interface B{
    b: boolean;
    c: number;
}

联合类型 A | B 的表达式可分配给 AB。它必须具有 AB(或两者)

的属性
const oA: A | B = {
    a: 6,
    c: 6
}

const oB: A | B = {
    b: true,
    c: 6
}

const oC: A | B = {
    a: 6,
    b: true
    c: 6
}

但是像A | B这样的类型有什么操作呢? 只有同时属于 AB

的那些
oA.c = 1; // valid

交集类型 A & B,如果它可同时分配给 A 和 B(因此必须同时具有 A 和 B 的属性)。

const obj: A & B = {
    a: 6,
    b: true
}

更新

你问"why does A & B in your example can take b prop? it's not assignable to type A"

这显然不是真的。 任何具有 A 的所有属性的类型都可以分配给 A。额外的属性没有害处:

const aAndExtraProp = {
  a: 6,
  d: 6
};

const ca0: A = aAndExtraProp;

您可能对对象文字的 Excess Property Checks 感到困惑:

Object literals get special treatment and undergo excess property checking when assigning them to other variables, or passing them as arguments. If an object literal has any properties that the “target type” doesn’t have, you’ll get an error:

const ca1: A = {
  a: 6,
  d: 6 //ERROR
};

Think from the perspective of what a union type accepts. The set of things that can be assigned to a string | number field is the union of the set of all strings and the set of all numbers. The set of things that can be assigned to a string & number is nothing because there is no overlap in the set of all strings and the set of all numbers.

I think you're picturing it as a set operator on the fields rather than a set operator of the sets of what each type represents.

///////////////////////

This is mathematical terminology: a "type" is a set of all its possible values, e.g. boolean = {true, false};. Now union of types T and U is a set consisting of values in T or in U (i.e. T merged with U); similarly intersection of values in both T and U (i.e. common part of them).

A member is accessible iff it's on all possible values. For union, value of type T|U may be T or may be U. We don't know which so only common attributes are legal. As you can see, operation on type implies different but complementary operation on members. This is a consequence of de Morgan laws.

https://www.reddit.com/r/typescript/comments/9qduq3/why_is_type_intersection_called_like_that_its/

以下示例可帮助您了解 TS 并集和交集的工作原理:

interface A {
  a1: string,
  a2: string,
}

interface B {
  b1: string,
  b2: string;
}

type UnionAB = A | B;
type IntersectionAB = A & B;

const unionAB1: UnionAB = {
  a1: 'xxx',
  a2: 'xxx',
  b1: 'xxx',
  b2: 'xxx',
};

const unionAB2: UnionAB = {
  a1: 'xxx',
  a2: 'xxx',
};

const unionAB3: UnionAB = {
  b1: 'xxx',
  b2: 'xxx',
};

// Error
// Property 'a1' does not exist on type 'B'.
console.log(unionAB3.a1);

const unionAB4: UnionAB = {
  a1: 'xxx',
  a2: 'xxx',
  b2: 'xxx',
};

// Error
// Property 'b1' does not exist on type 'UnionAB'.
// Property 'b1' does not exist on type 'A'.
console.log(unionAB4.b1);


// Error
// Type '{ a1: string; b2: string; }' is not assignable to type 'UnionAB'.
// Property 'b1' is missing in type '{ a1: string; b2: string; }' but required in type 'B'.
const unionAB5: UnionAB = {
  a1: 'xxx',
  b2: 'xxx',
};

const intersectionAB1 : IntersectionAB = {
  a1: 'xxx',
  a2: 'xxx',
  b1: 'xxx',
  b2: 'xxx',
};

// Error
// Type '{ a1: string; a2: string; b1: string; }' is not assignable to type 'IntersectionAB'.
// Property 'b2' is missing in type '{ a1: string; a2: string; b1: string; }' but required in type 'B'.
const intersectionAB2 : IntersectionAB = {
  a1: 'xxx',
  a2: 'xxx',
  b1: 'xxx',
};

// Error
// Type '{ a2: string; b1: string; b2: string; }' is not assignable to type 'IntersectionAB'.
// Property 'a1' is missing in type '{ a2: string; b1: string; b2: string; }' but required in type 'A'.
const intersectionAB3 : IntersectionAB = {
  a2: 'xxx',
  b1: 'xxx',
  b2: 'xxx',
};