Partial Types in Typescript

I’ve been learning Typescript in a bit more depth lately and have come across the Typescript Utility Types which on the surface look very useful. Reading through the documentation though I struggled to see how they could be practically applied without “forcing” it unecessarily.

I finally came across a great use case for the Partial Utility type and thought I would share. It also helps me to understand the example even more

Example using Google Enhanced Ecommerce

This example looks at Google Analytic’s Enchanced Ecommerce which is used to send shopping cart behavior data and purchase data to Google Analytics.

This particlar example looks at the ‘Purchase’ action. The action to be pushed to the Data Layer looks like the below:

dataLayer.push({
  ecommerce: {
    purchase: {
      actionField: {
        id: "T12345", // Transaction ID. Required for purchases and refunds.
        affiliation: "Online Store",
        revenue: "35.43", // Total transaction value (incl. tax and shipping)
        tax: "4.90",
        shipping: "5.99",
        coupon: "SUMMER_SALE",
      },
      products: [
        {
          // List of productFieldObjects.
          name: "Triblend Android T-Shirt", // Name or ID is required.
          id: "12345",
          price: "15.25",
          brand: "Google",
          category: "Apparel",
          variant: "Gray",
          quantity: 1,
          coupon: "",
        },
      ],
    },
  },
})

As can be seen there are two distinct ‘types’, the actionField and the Product type. Within the Product, the interface may look like:

interface Product {
  id: string;
  name: string;
  brand?: string;
  category?: string;
  variant?: string;
  price?: number;
  quantity?: number;
  coupon?: string;
  position?: number;
}

The actionField looks like the below:

interface ActionField {
  id: string;
  affiliation?: string;
  revenue?: number;
  tax?: number;
  shipping?: number;
  coupon?: string;
  list?: string;
  option?: string;
}

Note the ? next to some properties denotes it is an optional field. The remaining are required fields which must be sent to Google in order of Analytics to process the data properly.

Partial actionField

The actionField has one mandatory property, the id, which is the transaction id. Say in order to get the transaction ID, you require a successful payment. In that instance, the id would be unknown until the payment is successful, however the other fields would be known as we know what product the user is buying and how much it costs. Therefore we can create Partial<ActionField> while we’re waiting for the transaction to complete.

Note the way to partial type is constructed. By wrapping our type actionField within the Partial type, e.g. Partial<ActionField>.

i.e.

interface ActionField {
  id: string,
  affiliation?: string,
  .. //other properies ommitted for brevity
}

becomes

interface ActionField {
  id?: string,
  affiliation?: string,
  .. //other properies ommitted for brevity
}

See the below example. This outlines a user making a purchase, awaiting the result of the transaction, then combining the transaction id with the already known data so it can be sent to Google at that point.

function completePurchase(): Promise {
  // Some service sends the transaction data
  // to a payment provider
}

function sendDataToGoogle(data: ActionField) {
  // Send to google
}

// Note the below would not work as it is expecting the `id` field
let invalidTransactionData: ActionField = {
  affiliation: "My store",
  revenue: "22.00",
}

// Create a partial Type as we don't know the id yet
let knownTransactionData: Partial<ActionField> = {
  affiliation: "My store",
  revenue: "22.00",
}

// The user clicks on the purchase button. When we get the
// transaction data back from the payment provider, we can
// spread the id into the transactionData and send it to Google
completePurchase().then(transactionData => {
  const { id } = transactionData
  knownTransactionData = { ...knownTransactionData, id }
  sendDataToGoogle(knownTransactionData)
})

This is just a quick example similar to a use case I found and thought it useful to put my thoughts on page! The syntax for creating utility types I find is easy to read and explicit in their intentions so I think they’re a handy thing to know in your Typescript toolbelt.

Thanks

Get in contact

Complete the form below to get in contact with me 😃