How to Create Custom Valueof Similar to Keyof to Return Union of Property Value Types in TypeScript

David Mbochi Njonge Feb 02, 2024
  1. Return Union of Property Value Types Using valueof in TypeScript
  2. Return Union of Property Value Types Using keyof and typeof in TypeScript
  3. Get Property Value Type Using the Individual Keys in TypeScript
  4. Check Key-Value at Compile Time Using Generics in TypeScript
How to Create Custom Valueof Similar to Keyof to Return Union of Property Value Types in TypeScript

In this tutorial, we will learn the different ways we can use to return the types that make up our property or an object.

There are three ways that we can use to realize this functionality. One of the methods leverages generics to create a custom type named valueof that returns all the union types of the property.

The second method uses keyof and typeof types to return all the union types of the property. The third method uses individual keys to return a single type as required.

We will also learn to restrict the key-value entries at compile time if they are not of the same type by leveraging generics and indexed access types.

Return Union of Property Value Types Using valueof in TypeScript

Go to visual studio code and create a folder named typescript-types or use any name you prefer. Create a file named value-types-using-valueof.ts under the folder.

Copy and paste the following code into the value-types-using-valueof.ts file.

type ValueOf<T> = T[keyof T];

type Customer = {
    firstName: string,
    lastName: string,
    doB: Date,
}

type ValueOfCustomer = ValueOf<Customer>

let customer: Customer  ={
    firstName: 'john',
    lastName: 'doe',
    doB: new Date(2022,12,6),
}

function logDetails(customerInfo: ValueOfCustomer){
   console.log(customerInfo)
}

logDetails(customer.firstName)
logDetails(customer.lastName)
logDetails(customer.doB)
logDetails(500)// Error - The union does not include type number

First, we define a generic type ValueOf<T> and assign it to the T[keyof T]. The T means that any type can be passed to the ValueOf, whether property or an object.

The keyof returns the union of all the key types that belong to the passed type.

We have created the Customer object that contains the properties firstName, lastName, and doB. The first two properties are type string, and the last property is type Date.

Next, we have created a type named ValueOfCustomer by passing Customer to the ValueOf<Customer> generic type. The ValueOfCustomer is our new type composed of the union of all key times in the Customer object.

That means the ValueOfCustomer can only accept values with the type string and date.

To verify, we have created a method named logDetails() that accepts a parameter of type ValueOfCustomer and used it to log the firstName, lastName, and doB of Customer.

Note that if we try to pass a value that is not of type string or Date, such as a number in the method, we will get an error because the method argument accepts only a string or a number.

Return Union of Property Value Types Using keyof and typeof in TypeScript

In the same folder, create a file named value-types-using-keyof-and-typeof.ts. Copy and paste the following code into the file.

type Customer = {
    firstName: string,
    lastName: string,
    doB: Date,
}

const customer: Customer  ={
    firstName: 'john',
    lastName: 'doe',
    doB: new Date(2022,12,6),
} as const

type customertypes = typeof customer[keyof Customer]

function getCustomerInfo(theCustomerTypes: customertypes){
    console.log(theCustomerTypes)
}

getCustomerInfo(customer.firstName)
getCustomerInfo(customer.lastName)
getCustomerInfo(customer.doB)
getCustomerInfo(234)//Error - The union does not include type number

In the above code, we have defined our Customer type containing the properties firstName, lastName, and doB. The first two properties are type string, and the last property is type Date.

The Customer object is initialized with concrete values for each property in the object. The type named customertypes has been created and assigned to typeof customer[keyof customer].

In the last example, we mentioned that keyof returns the union of all the key types. And this has been applied to our Customer object to do the same.

The typeof will return all types obtained from the Customer object, which is realized with the help of keyof, as shown in the code.

To verify this, we have created a method named getCustomerInfo() that accepts a parameter of type customertypes and used it to log the values of our Customer object.

Note that if we try to pass a value that is not of type string or Date such as a number, in the method, we will get an error because the new type does not contain a type number.

Get Property Value Type Using the Individual Keys in TypeScript

In the above two examples, we have covered how to retrieve the union of all the value types, but in some cases, you might only be interested in one type of object.

In this example, you will learn how to retrieve a single value type of an object using the individual keys.

Under the same folder, create a file named individual-keys.ts. Copy and paste the following code into the file.

type Customer = {
    firstName: string,
    lastName: string,
    doB: Date,
}

type date = Customer['doB']

function getDateOfBirth(doB: date): Date{
    return doB;
}

let customer: Customer  ={
    firstName: 'john',
    lastName: 'doe',
    doB: new Date(2022,12,6),
}

getDateOfBirth(customer.doB)
getDateOfBirth(123)//Error - Method accepts a single parameter of type date

In this example, we have reused the same customer definition as in previous examples. The date type has been created by referencing the doB key from the customer definition using Customer['doB'].

This means the new date type is of type Date. The getDateOfBirth() contains a single parameter of type date and has been used to verify that only date types can be passed to it, as shown in the code.

If we try to pass a value that is not of type date, such as a number, we will get an error because the parameter is restricted to a single type.

Check Key-Value at Compile Time Using Generics in TypeScript

As seen in the previous examples, an object is composed of a key and a value. Sometimes we might be faced with a requirement to change the values of an object based on its keys.

In this tutorial, we will learn to ensure that the values we pass are checked at compile time to ensure they are of the same type as the keys.

Create a file named key-value-checking.ts under the same folder. Copy and paste the following code into the file.

type Shipment = {
    containerItems: string,
    containerSerial: string
    shipmentDate: Date
}

declare function updateShipment<K extends keyof Shipment>(key: K, value: Shipment[K]): void;

updateShipment('containerItems','flowers')
updateShipment('containerSerial','def456');
updateShipment('shipmentDate',new Date(2018,3,14))
updateShipment('shipmentDate',1337)// Error- Shipment object does not contain type number

In the above code, we have defined an object named Shipment containing the parameters containerItems, containerSerial, and shipmentDate.

The first two properties are type string, and the last property is type Date. We have defined a generic method named updateShipment().

The updateShipment() method accepts two parameters where one is a key and the second is a value for the Shipment object.

The key must be any type of the Shipment object keys, and these are checked using <K extends keyof Shipment> in the angle brackets parameter.

Since we have the key K, we can restrict the values passed to this key by indexing the keys for the Shipment object using Shipment[K]. With this definition, every value we enter for the key must be the same type as the key.

Note that if you try to pass a value not defined in the Shipment object, such as a number, the compiler flags the problem.

David Mbochi Njonge avatar David Mbochi Njonge avatar

David is a back end developer with a major in computer science. He loves to solve problems using technology, learning new things, and making new friends. David is currently a technical writer who enjoys making hard concepts easier for other developers to understand and his work has been published on multiple sites.

LinkedIn GitHub

Related Article - TypeScript Type