This TypeScript Problem will Challenge your Mind
Using Mapped Types to Filter Data

Join our Vibrant Discord Community for exclusive information and insightful discussions
TypeScript is a programming language filled with many surprises, both good and bad.
In this article, we look over a good surprise TypeScript offers, which is TypeScript Mapped Types.
We will discuss the use of Mapped Types to solve a realistic problem.
By the end, you will have grasped this concept fully, and gained the ability to apply this concept and directly improve your applications.
So without further ado, lets jump right in!
The Problem
Here we are using the country-to-currency package to represent mappings between Country Codes and a Currencies as follows:
import countryToCurrency, {
Currencies,
// Renamed to `CountryCodes` because it seems
// easier to understand.
Countries as CountryCodes,
} from "country-to-currency"
// Defined for readability purposes
type CountryToCurrency = typeof countryToCurrency
// type Currencies = "GBP" | "USD" ...
// type CountryCodes = "GB" | "US" ...
// type CountryToCurrency = { GB: "GBP", US: "USD" ... }
“So… what is the problem?”
Well, it would be nice if we could return specific CountryCodes
, based on an input Currency
, all while maintaining type safety.
Let’s illustrate what I mean through this code:
type Result = CountryCodesFromCurrency<"GBP">
// Result Type: "GB" | "GG" | "IM" | "JE"
Lets also visualize this problem using a diagram for better understanding:

We are essentially trying to reverse-map a currency to their corresponding country codes.
The Solution
It turns out there is an elegant solution for this using Mapped Types.
Mapped types allow you to create new types based on existing ones by applying a transformation to each property in the original type.
// Here is a basic example of a `Mapped Type`
// This will take in a type and change all the values to boolean.
// While keeping the keys intact.
type OptionsFlags<Type> = {
[Property in keyof Type]: boolean;
};
To achieve reverse-mapping from Currencies
to CountryCodes
, here is the logic we need to follow:
- Define a Mapped type.
- For each key (
CountryCode
) in ourCountryToCurrency
mappings, we check that the value corresponds to our inputThisCurrency
. - If it does, keep this property.
- It it doesn’t, remove this property by setting the key type as
never
.
And here is the code to make this happen:
// If you do not understand this, please see below
// this code block where I break it down.
type FilterMappingsFor<ThisCurrency extends Currencies> = {
[CountryCode in keyof CountryToCurrency
as CountryToCurrency[CountryCode] extends ThisCurrency
? CountryCode : never]: CountryToCurrency[CountryCode]
}
- We define a Mapped type called
FilterMappingsFor
which takes inThisCurrency
for which you want the country codes for. - We iterate through each
CountryCode
key. - For each
CountryCode
, compare the corresponding currency (CountryToCurrency[CountryCode]
) to our input:ThisCurrency
. - If the currencies match, keep the current property intact.
- If they don’t match, set the key to
never
, which effectively removes the current property.
We are nearly done!
Currently, our FilterMappingsFor<ThisCurrency>
type returns the correct mappings, but we only require the CountryCodes
.
Lets define a new type CountryCodesFromCurrency
to extract every key from our filtered mappings:
// Since FilterMappingsFor returns the correct key value pairs
// of country codes and currencies, this new type will extract
// only what we want; the country codes.
type CountryCodesFromCurrency<ThisCurrency extends Currencies> =
keyof FilterMappingsFor<ThisCurrency>
And finally, we may test this by defining a new types Result1
and Result2
as follows:
type Result1 = CountryCodesFromCurrency<"GBP">
type Result2 = CountryCodesFromCurrency<"NIO">
// Output1: "GB" | "GG" | "IM" | "JE"
// Output2: "NI"
If you enjoyed this article, please make sure to Subscribe, Clap, Comment and Connect with me today! 🌐