3.5 Intersection Types
Intersection types represent values that simultaneously have multiple types. A value of an intersection type A & B is a value that is both of type A and type B. Intersection types are written using intersection type literals (section 3.8.7).
An intersection type encompasses an ordered set of constituent types. While it is generally true that A & B is equivalent to B & A, the order of the constituent types may matter when determining the call and construct signatures of the intersection type.
Intersection types have the following subtype relationships:
- An intersection type I is a subtype of a type T if any type in I is a subtype of T.
- A type T is a subtype of an intersection type I if T is a subtype of each type in I.
Similarly, intersection types have the following assignability relationships:
- An intersection type I is assignable to a type T if any type in I is assignable to T.
- A type T is assignable to an intersection type I if T is assignable to each type in I.
For purposes of property access and function calls, the apparent members (section 3.11.1) of an intersection type are those that are present in one or more of its constituent types, with types that are intersections of the respective apparent members in the constituent types. The following examples illustrate the merging of member types that occurs when intersection types are created from object types.
interface A { a: number }
interface B { b: number }
var ab: A & B = { a: 1, b: 1 };
var a: A = ab; // A & B assignable to A
var b: B = ab; // A & B assignable to B
interface X { p: A }
interface Y { p: B }
var xy: X & Y = { p: ab }; // X & Y has property p of type A & B
type F1 = (a: string, b: string) => void;
type F2 = (a: number, b: number) => void;
var f: F1 & F2 = (a: string | number, b: string | number) => { };
f("hello", "world"); // Ok
f(1, 2); // Ok
f(1, "test"); // Error
The union and intersection type operators can be applied to type parameters. This capability can for example be used to model functions that merge objects:
function extend<T, U>(first: T, second: U): T & U {
// Extend first with properties of second
}
var x = extend({ a: "hello" }, { b: 42 });
var s = x.a;
var n = x.b;
It is possible to create intersection types for which no values other than null or undefined are possible. For example, intersections of primitive types such as string & number
fall into this category.