Manipulation Continues with TypeScript’s Type Operators
Expanding Your TypeScript Toolbox with ‘keyof’ and ‘typeof’
TypeScript offers powerful type operators such as ‘typeof’ and ‘keyof’ that enable developers to effortlessly extract and manipulate types. With these operators, there’s no need to explicitly specify the types, making type extraction and manipulation a smooth process.
With the ‘typeof’ operator, developers can reference the type of variables, functions, or classes as values, enabling dynamic type querying. Similarly, the ‘keyof’ operator empowers developers to extract keys from object types, providing advanced possibilities for type manipulation.
In this article, with the help of clear examples and explanations, we’ll shed light on their potential, equipping you with the knowledge to leverage them effectively in your TypeScript projects.
‘typeof’ Type Operator
In TypeScript, the typeof
type operator allows you to capture the type of a value or expression at compile-time. It enables you to refer to the type of a variable, function, or class without actually creating an instance of it.
The typeof
operator is used in the following format: typeof x
, where x
is a value or expression you want to capture the type of.
Let’s see some examples:
- The
typeof
operator can be used to create a custom type based on the type of variables.
2. By combining the typeof
operator and theReturnType
utility type, you can define a custom type that only accepts data types matching the return type of a specific function.
The ReturnType
is a utility type that extracts the return type of a function, allowing you to capture and utilize the specific type that a function returns. If you want to learn more about ReturnType
, check out the article titled TypeScript’s Type Manipulations which explains it in detail.
Limitations
“TypeScript intentionally limits the sorts of expressions you can use
typeof
on. Specifically, it’s only legal to usetypeof
on identifiers (i.e. variable names) or their properties. This helps avoid the confusing trap of writing code you think is executing, but isn’t.”
Here is an example:
PersonObjectType = typeof personObject;
—
is valid, of type { name: string; age: number; }PersonAgeType = typeof personAge;
— is valid, of type number.PersonNameTypeValid = Person["name"];
— Similarly topersonAge
, the lookup typePerson["name"]
allows accessing the property(‘name’) dynamically based on its key.
The lookup type is closely related tokeyof
and is used to retrieve the type of a specific property based on its key.
‘keyof’ Type Operator
The keyof
index type operator allows you to extract the union of all keys from a given object type. It enables you to work with keys dynamically and perform various operations based on those keys. The keyof
operator is commonly used in combination with mapped types.
Keep scrolling for examples below.
- Indexed Access and Key Retrieval
The primary use ofkeyof
is to retrieve all the keys from an object type.
Thekeyof
operator is often used with indexed access types to access or manipulate specific properties of an object type dynamically.
Let’s break down the code step by step:
DataType
refers to the type of the objects in theitems
array.KeyType
represents the type of the key that is passed to the function.- By using
KeyType extends keyof DataType
, you're enforcing that thekey
parameter provided to the function must be a valid key of theDataType
object.
—extends
is a TypeScript keyword used to constrain the generic type parameter.
—keyof SomeType
is a TypeScript operator that represents the union of all possible keys of theSomeType
object. It extracts the keys of theSomeType
object as a string or a string literal type. DataType[KeyType]
is an indexed access type in TypeScript. It retrieves the type of the property inDataType
that corresponds to theKeyType
.- Mind the
[]
, that denotes an array type in TypeScript.
One cool 😎 and convenient feature is that when invoking the function and selecting the key, by typing an empty string (""
), you will automatically get the available options derived from the DataType
object.
Finally, the available outputs in this example are:
2. Mapped Types and Constraints
The shown below can be helpful when you want to ensure that certain properties in an object type cannot be modified after initialization.
Let’s break down the code step by step:
- We first define a type
Person
(an example object type) representing an object with two properties:name
of typestring
andage
of typenumber
. - The
ReadonlyPerson
type is defined as a generic type that takes a type parameterT
. It represents an object type where all the properties are marked asreadonly
. { readonly [K in keyof T]: T[K]; }
defines an object type with the same keys asT
, where each property is ofreadonly
access.
—[K in keyof T]
is a mapped type syntax that iterates over each keyK
in the union of all keys (keyof T
) of typeT
.type ReadonlyPersonType = ReadonlyPerson<Person>;
Here, we use theReadonlyPerson
type and specifyPerson
as the type argument (T
). This creates a new typeReadonlyPersonType
where all properties arereadonly
versions of the corresponding properties inPerson
.- By creating a variable of the type
ReadonlyPersonType
we ensure its immutability for the properties of aPerson
object.
‘keyof typeof’
The combination keyof typeof
allows you to extract keys from a type. It is typically used to retrieve the keys of an object or the properties of a class as a union type. For example:
interface Fruit {
name: string;
color: string;
taste: string;
}
type FruitKeys = keyof typeof Fruit;
// Equivalent to: type FruitKeys = "name" | "color" | "taste"
function getProperty(fruit: typeof Fruit, key: FruitKeys) {
return fruit[key];
}
const apple: Fruit = {
name: "Apple",
color: "Red",
taste: "Sweet",
};
const color = getProperty(apple, "color"); // Accessing property "color" from the apple object
console.log(color); // Output: "Red"
💡 Consider using an open-source toolchain such as Bit for applying a component-driven approach to building your TypeScript projects. With Bit you can easily share, discover, and reuse individual components across different projects, which can significantly reduce code duplication and improve code quality.
Learn more:
If you’d like to further dive into TypeScript, you might find some of my other articles on type manipulation useful. For example, you can check out TypeScript’s Type Manipulations.
I’d also like to give a shout-out to Jun Tsunokawa for his article on “How to Use keyof typeof in TypeScript”, where he provides a great example in the world of React!
Conclusion
We’ve explored the power of TypeScript’s ‘typeof’ and ‘keyof’ operators, and explained them clearly using examples giving you the tools to use them effectively in your projects. I hope you found this post helpful.
Stay tuned for future content! If you’re new here, feel free to explore the TypeScript library 📚, or my other posts and follow me for updates and more valuable insights.
By buying me a virtual croissant on Buy Me a Coffee, you can directly support my creative journey. Your contribution helps me continue creating high-quality content. Thank you for your support!
Build Apps with reusable components, just like Lego
Bit’s open-source tool help 250,000+ devs to build apps with components.
Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.
Split apps into components to make app development easier, and enjoy the best experience for the workflows you want: