Partial matches in Typescript

Last updated October 1, 2021 by Jacob Paris

I have a type Contact that gets used in multiple places. A Person can have a contact, so it becomes a field on their type, but also a Company can have a contact.

export interface Contact {
firstName: string
lastName: string
phoneNumber: string
}
export type Person = {
id: string
contact: Contact
}
export type Company = {
id: string
contact: Contact
}
const company = {
id: uuid(),
contact: {
phoneNumber: '+123456790',
},
}

produces the error

Type '{ phoneNumber: string; }' is missing the following properties from type 'Contact': firstName, lastName

Typescript expects that all implementations of the Contact type use every defined field, but since a business doesn't need to have a first or last name, I don't want to have to add those.

The solution

There are several typescripty ways to solve this

New type

One solution is to stop messing around with reusability and just make a new type for this clearly different use-case.

export interface CompanyContact {
phoneNumber: string
}
export type Company = {
id: string
contact: CompanyContact
}

Partial

The Partial type makes every field optional

export type Company = {
id: string
contact: Partial<Contact>
}

Pick

Pick allows you to pick specifically which fields you want

export type Company = {
id: string
contact: Pick<Contact, 'phoneNumber'>
}