Did you know that TypeScript comes with a bunch of built in string manipulator types? That means we can easily transform a string
type into uppercase, lowercase, or capitalized versions of itself. When might this be useful? In lots of situations where you have a fixed set of string values, for example whenever you have a set of strings from an object using something like keyof.
To transform a string into a different version by defining a new type along with one of the type manipulators. For example, below we transform myType
into the capitalized version:
type myType = "hi there"
type capitalizedMyType = Capitalize<myType>
let myVar:capitalizedMyType = "Hi there";
In the above example, hi there
would throw an error - only Hi there
will work with a Capitalize
type. Similarly, we can uncapitalize a string using Uncapitalize
:
type myType = "HI THERE"
type uncapitalizedMyType = Uncapitalize<myType>
let myVar:uncapitalizedMyType = "hI THERE";
Above, only hI THERE
will work. Any other case will fail the check.
Uppercase and Lowercase Intrinsic Type Manipulation
Along with Capitalize
, we also have Uppercase
and Lowercase
. They both do exactly what you think they'd do - one changes all characters to uppercase, and the other to lowercase.
type myType = "this long sentence"
type bigMyType = Uppercase<myType>
let myVar:bigMyType = "THIS LONG SENTENCE"
Lowercase intrinsic type manipulation
Above we've created a type which is the uppercase version of myType
. Here is the same example, but in the other direction: making the lowercase version:
type myType = "THIS LONG SENTENCE"
type smallMyType = Lowercase<myType>
let myVar:smallMyType = "this long sentence"
Using with template literals
These types become very useful when working with template literals, where we can enforce a string literal to use a lowercase version - for example for an ID. Here is a version where we have a set number of strings, and we only want to use the lowercase version in the ID, as part of the versionId
type:
type versions = "DEV" | "PROD" | "STAGING"
type versionPrefix = "gold-" | "beta-" | "alpha-"
type versionId = `${versionPrefix}${Lowercase<versions>}`
let currentVersion:versionId = "gold-dev"
Above, we have two sets of union types, and we combine them into one versionId
. Here, we only accept lowercase letters, but version
is uppercase. We can transform it with Lowercase
, so gold-dev
is valid.
Using with keyof objects
In a similar way, we may receive an object from an API or elsewhere, which has odd or uneven casing. To normalise this, we can use intrinsic type manipulations. Below, I am using keyof
to get all the keys in myObject
, and making them all lowercase too.
type myObject = {
firstName: string,
Age: number,
Lastname: string
}
type keys = Lowercase<keyof myObject>
let getObjectKey:keys = "firstname"
keys
only has the following valid values: firstname | age | lastname
. In this example, using intrinsic string manipulation like this can be an easy way to create clean types when the data we have at our disposal has issues.