liveBook · Manning

Property merge

As explained in Essential TypeScript 5, Third Edition

A property merge is the formation of a shared property in an intersection by intersecting the property types contributed by its constituent types.

A property merge determines the type of a shared property in an intersection by intersecting the types contributed by each constituent type. Matching types remain usable; incompatible primitive types produce never. section 10.3.2

Use these rules when reading or designing intersected object types:

  • Combine distinct properties into one object shape. Person & Employee provides both types' properties. section 10.3.2
  • Treat a shared property as the intersection of its types. number & string becomes never, so neither number nor string can satisfy it. section 10.3.2
  • Prefer compatible shape types when shared data must contain both parts, such as { phone: number } & { name: string }. section 10.3.2
  • Expect same-named methods to merge their signatures, producing overload-like behavior that can be difficult to implement. section 10.3.2

Contact data

Person & Employee can represent a person with employment details. If both define contact differently as primitive types, assignments fail because the merged contact type is never. section 10.3.2

Listing 10.19 Using types in an intersection in the index.ts file in the src folder
type Person = {
    id: string,
    name: string, 
    city: string
};

type Employee = {
    id: string,
    company: string,
    dept: string
};

type EmployedPerson = Person & Employee;

function correlateData(peopleData: Person[], staff: Employee[])
        : EmployedPerson[] {
    const defaults = { company: "None", dept: "None"};
    return peopleData.map(p => ({ ...p, 
        ...staff.find(e => e.id === p.id) || { ...defaults, id: p.id } }));
}

let people: Person[] = 
    [{ id: "bsmith", name: "Bob Smith", city: "London" },
     { id: "ajones", name: "Alice Jones", city: "Paris"},
     { id: "dpeters", name: "Dora Peters", city: "New York"}];

let employees: Employee[] = 
    [{ id: "bsmith", company: "Acme Co", dept: "Sales" },
     { id: "dpeters", company: "Acme Co", dept: "Development" }];

let dataItems: EmployedPerson[] = correlateData(people, employees);

function writePerson(per: Person): void {
    console.log(`Person: ${per.id}, ${per.name}, ${per.city}`);                
}

function writeEmployee(emp: Employee): void {
    console.log(`Employee: ${emp.id}, ${emp.company}, ${emp.dept}`);
}

dataItems.forEach(item => {
    writePerson(item);
    writeEmployee(item);
});

Inspect the complete Person, Employee, EmployedPerson, and correlateData example. section 10.3.2

How Essential TypeScript 5, Third Edition covers it

How deep it goes
Explains distinct properties, incompatible primitive results, compatible shapes, and method-signature intersections.
Examples
Uses Person and Employee records, contact properties, getContact methods, compiler errors, and generated declaration types.
What you can do after
Apply it via TypeScript to combine object shapes and diagnose impossible shared-property or method intersections.
How it connects
Connects intersection types with object shapes, primitive types, method overloading, and declaration files.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Essential TypeScript 5, Third Edition. The section links point to the parts of the book it draws on.