This TypeScript Trick Will Blow Your Mind
Extracting Custom Types from String Arrays
“In the world of TypeScript, custom types emerge from string arrays like hidden gems.”
Join our Vibrant Discord Community for exclusive information and insightful discussions
TypeScript is an amazing tool to manipulate existing data and develop great practices.
Today we will explore how to extract a full name from a string array in the correct manner to ensure a clean type-safe output.
So without further ado… Let's get right into it.
The Problem
Let's begin by examining this code and understanding the problem with it:
- This code uses an array of
names
to be searched. - The function
findName
takes a stringsurname
and returns the associated full name.
The problem arises when you input "Doee"
into the function findName
.
This inconspicuous spelling error gives us an undefined
output, which may cause bugs later down the line since nothing is stops us from making this error.
This is where TypeScript jumps in.
If we ensure findName
only accepts literal Surnames
, i.e. Craciun, Doe, Pigeon, then the compiler should shout at us when we enter inputs such as "Doee"
which do not exist in the names
array.
The Solution
We have established the only valid arguments for findName
needs to consist of all existing surnames.
To achieve this, we create a generic type called ExtractSurname
.
The code for ExtractSurname
may seem difficult, but we will dissect it step-by-step:
1. Here ExtractSurname
takes a generic argument T
, which refers to any literal string
using the extends
operator.
In ExtractSurname<”Daniel”>
, The value of T
would equal "Daniel"
.
2. Next we apply the Typescript ternary operator, which is similar to the JavaScript ternary, but we are comparing types instead of real data.
3. We know the format of our names
array is “<Name> <Surname>”, so here the infer
keyword extracts subtypes from T
.
In ExtractSurname<”Daniel Craciun”>
:
infer Firstname
=“Daniel”
infer Surname
=“Craciun”
4. Lastly, if the input satisfies our format of “<Name> <Surname>”, return the Surname
as a type, else return null
.
Ok, so we have our ExtractSurname
type ready.
Now we need a Surname
type to represent all the surnames inside names
.
1. names
satisfies the format from ExtractSurname
of “<Name> <Surname>”
2. We use as const
to narrow down the type of names
to an array of literal strings.
This means we cast the type of names
from string
to:
readonly [“Daniel Craciun”, “John Doe”, “Harry Pigeon”]
.
3. The argument (typeof names)[number]
represents the type of each indexed element inside names
:
“Daniel Craciun” | “John Doe” | “Harry Pigeon”
4. Finally, this is the resulting type of Surname
:
The last step is to update our findName
function defined earlier with a new function findNameUsingSurname
as follows:
And here is the Typescript compiler performing its magic as we expected:
If you enjoyed this article, please make sure to Subscribe, Clap, Comment and Connect with me today! 🌐