1. 14
  1.  

  2. 1

    When TypeScript has a union type A | B, it allows you to access all the properties common to both A and B (i.e. the intersection of members).

    I don’t think this is a Typescript thing, but where does the idea that a union of types gives you the intersection of their members come from? This seems like really counterintuitive naming - I would have expected the union of two types to be like a set union, but it seems like it’s not.

    1. 1

      A union type is a type that provides the interface that all member types can satisfy.

      If you have

      type A
        foo
        bar
      end type A
      
      type B
        bar
        baz
      end type B
      

      the type A | B can be either

      (what they do)
      type A | B
        bar
      end type A | B
      

      or

      (what you seem to propose)
      type A | B
        foo
        bar
        baz
      end type A | B
      

      In TS3.3’s scenario, any object that can be put in some container for A | B objects will be able to access their bar property (no matter if that’s a method, function, property, variable, …). In your scenario, if you put an A into an A | B container, accessing their baz property will fail.

      1. 2

        Thanks for the explanation, but I didn’t mean to propose a change in the behaviour. I probably should have been clearer about what I was saying: why is the term “union” used when the behaviour (as described in the very same sentence) is “intersection”?

        1. 2

          The set of values allowed to be assigned to the variable is the union of A values and B values; this where the term “union type” comes from. It’s only the set of values allowed to be read from the variable that is the intersection of A values and B values.

          1. 2

            The “problem” with that construct is that it expands in one direction and restricts in another, similar to contravariance in related language features (subclassing, generics):

            An “A | B” can safely host elements that are A or are B (that’s where the “union” name comes from), but at the price that the interface you can expect must be the intersection of A’s and B’s interfaces (since you don’t know which subtype you’ll grab at any given moment). So it’s a union type with an intersection interface.

            What would an intersection type look like?

            “A & B” only works in a language where any object can be part of multiple classes (using the terms loosely here, objects needn’t be “object oriented” objects and classes could also be interfaces etc), and with that statement you’d mandate that a variable of type A & B can only host an object that implements both the A interface and the B interface, so that variable can’t hold just any A or any B.

            And that means when you have an intersection type (it’s stricter than A or B alone), it’ll have an interface that’s the union of A’s and B’s and therefore is the same or larger than either of them.

            Finally, there’s the C style union type:

            union { struct a a; struct b b; };

            This is covariant-alike in that it both widens the selection of types you can assign to it and allows you to use either interface on the stored data. However in the general case that extended interface won’t make sense, since you’re simply reading the same data in two different ways, one of them usually looking like garbage - which is why C unions are typically used only in very particular situations (either with some manually maintained type tag to state which interface to use, which reduces it to the contravariant-alike case or with very particular memory layouts)

      2. 1

        Why does this have the dotnet tag? I don’t see anything related to .NET in here.