How to Create Custom Valueof Similar to Keyof to Return Union of Property Value Types in TypeScript
-
Return Union of Property Value Types Using
valueof
in TypeScript -
Return Union of Property Value Types Using
keyof
andtypeof
in TypeScript - Get Property Value Type Using the Individual Keys in TypeScript
- Check Key-Value at Compile Time Using Generics 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 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