Objects and unions

Combine requirements with intersections

Create a type that must satisfy two object shapes and recognize when one explicit object type is easier to read.

A union says a value is one type or another. An intersection says a value is one type and another. It combines requirements: the value must satisfy every member at once. You write it with &:

type User = { id: number; name: string }
type Timestamped = { createdAt: Date }

type SavedUser = User & Timestamped

A SavedUser needs the properties from User and the properties from Timestamped:

const user: SavedUser = {
  id: 1,
  name: 'Ada',
  createdAt: new Date()
}

Leave out createdAt and the assignment fails. The error names the member that was not satisfied:

error TS2322: Type '{ id: number; name: string; }' is not assignable to type 'SavedUser'.
  Property 'createdAt' is missing in type '{ id: number; name: string; }' but required in type 'Timestamped'.

The value is a fine User. It is not a Timestamped. So it is not the intersection.

Intersections earn their place when independent concerns meet in one value. Timestamped can decorate users, posts and comments without repeating the field in each type. A function that only cares about timestamps accepts Timestamped alone, and any SavedUser qualifies, thanks to structural typing.

Conflicting properties

Be careful when two members declare the same property with different types:

type A = { id: string }
type B = { id: number }
type Impossible = A & B

The id would have to be a string and a number at the same time. No value can do that, so TypeScript resolves the property to never. Every attempt to build one fails:

const value: Impossible = { id: 'a1' }
error TS2322: Type 'string' is not assignable to type 'never'.

Notice that the compiler does not reject the Impossible type itself. Declaring it is legal. Only every attempt to create a value for it fails. If you ever see never in an error about a property you defined twice, an intersection conflict is the usual cause.

When to prefer one explicit type

Deep intersections also produce hard-to-read errors. A missing property in A & B & C & D gets reported against the whole chain, and you have to work out which member wanted it.

My advice: if the combined shape is a core domain object, one you name, read and discuss often, write it as one explicit object type. Keep intersections for small, independent, reusable capabilities like Timestamped.

Try this on your own: combine { title: string } with { updatedAt: Date }, build a value that omits one property on purpose, and read the error.

Lesson completed